0.6.1
[libretro-ppsspp.git] / android / jni / MenuScreens.cpp
blob0f54e7c33974f1c353ededa3ef13e9ab9ef181a6
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 #include <cmath>
19 #include <string>
21 #include "base/display.h"
22 #include "base/logging.h"
23 #include "base/colorutil.h"
24 #include "base/timeutil.h"
25 #include "base/NativeApp.h"
26 #include "gfx_es2/glsl_program.h"
27 #include "input/input_state.h"
28 #include "math/curves.h"
29 #include "ui/ui.h"
30 #include "ui_atlas.h"
31 #include "util/random/rng.h"
32 #include "util/text/utf8.h"
33 #include "UIShader.h"
35 #include "../../GPU/ge_constants.h"
36 #include "../../GPU/GPUState.h"
37 #include "../../GPU/GPUInterface.h"
38 #include "../../Core/Config.h"
39 #include "../../Core/CoreParameter.h"
40 #include "../../Core/SaveState.h"
42 #include "MenuScreens.h"
43 #include "EmuScreen.h"
45 #ifdef USING_QT_UI
46 #include <QFileDialog>
47 #include <QFile>
48 #include <QDir>
49 #endif
52 // Ugly communication with NativeApp
53 extern std::string game_title;
56 static const int symbols[4] = {
57 I_CROSS,
58 I_CIRCLE,
59 I_SQUARE,
60 I_TRIANGLE
63 static const uint32_t colors[4] = {
65 0xFF6666FF, // blue
66 0xFFFF6666, // red
67 0xFFFF66FF, // pink
68 0xFF66FF66, // green
70 0xC0FFFFFF,
71 0xC0FFFFFF,
72 0xC0FFFFFF,
73 0xC0FFFFFF,
76 static void DrawBackground(float alpha) {
77 static float xbase[100] = {0};
78 static float ybase[100] = {0};
79 if (xbase[0] == 0.0f) {
80 GMRng rng;
81 for (int i = 0; i < 100; i++) {
82 xbase[i] = rng.F() * dp_xres;
83 ybase[i] = rng.F() * dp_yres;
86 glClearColor(0.1f,0.2f,0.43f,1.0f);
87 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
88 ui_draw2d.DrawImageStretch(I_BG, 0, 0, dp_xres, dp_yres);
89 float t = time_now();
90 for (int i = 0; i < 100; i++) {
91 float x = xbase[i];
92 float y = ybase[i] + 40*cos(i * 7.2 + t * 1.3);
93 float angle = sin(i + t);
94 int n = i & 3;
95 ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f));
99 // For private alphas, etc.
100 void DrawWatermark() {
101 // ui_draw2d.DrawTextShadow(UBUNTU24, "PRIVATE BUILD", dp_xres / 2, 10, 0xFF0000FF, ALIGN_HCENTER);
104 void LogoScreen::update(InputState &input_state) {
105 frames_++;
106 if (frames_ > 180 || input_state.pointer_down[0]) {
107 if (bootFilename_.size()) {
108 screenManager()->switchScreen(new EmuScreen(bootFilename_));
109 } else {
110 screenManager()->switchScreen(new MenuScreen());
115 void LogoScreen::render() {
116 float t = (float)frames_ / 60.0f;
118 float alpha = t;
119 if (t > 1.0f) alpha = 1.0f;
120 float alphaText = alpha;
121 if (t > 2.0f) alphaText = 3.0f - t;
123 UIShader_Prepare();
124 UIBegin();
125 DrawBackground(alpha);
127 ui_draw2d.SetFontScale(1.5f, 1.5f);
128 ui_draw2d.DrawText(UBUNTU48, "PPSSPP", dp_xres / 2, dp_yres / 2 - 30, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
129 ui_draw2d.SetFontScale(1.0f, 1.0f);
130 ui_draw2d.DrawText(UBUNTU24, "Created by Henrik Rydgard", dp_xres / 2, dp_yres / 2 + 40, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
131 ui_draw2d.DrawText(UBUNTU24, "Free Software under GPL 2.0", dp_xres / 2, dp_yres / 2 + 70, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
132 ui_draw2d.DrawText(UBUNTU24, "www.ppsspp.org", dp_xres / 2, dp_yres / 2 + 130, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
133 if (bootFilename_.size()) {
134 ui_draw2d.DrawText(UBUNTU24, bootFilename_.c_str(), dp_xres / 2, dp_yres / 2 + 180, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
137 DrawWatermark();
138 UIEnd();
140 glsl_bind(UIShader_Get());
141 ui_draw2d.Flush(UIShader_Get());
145 // ==================
146 // Menu Screen
147 // ==================
149 void MenuScreen::update(InputState &input_state) {
150 frames_++;
153 void MenuScreen::render() {
154 UIShader_Prepare();
155 UIBegin();
156 DrawBackground(1.0f);
158 double xoff = 150 - frames_ * frames_ * 0.4f;
159 if (xoff < -20)
160 xoff = -20;
161 if (frames_ > 200) // seems the above goes nuts after a while...
162 xoff = -20;
164 int w = LARGE_BUTTON_WIDTH + 40;
166 ui_draw2d.DrawTextShadow(UBUNTU48, "PPSSPP", dp_xres + xoff - w/2, 80, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_BOTTOM);
167 ui_draw2d.SetFontScale(0.7f, 0.7f);
168 ui_draw2d.DrawTextShadow(UBUNTU24, PPSSPP_VERSION_STR, dp_xres + xoff, 80, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_BOTTOM);
169 ui_draw2d.SetFontScale(1.0f, 1.0f);
170 VLinear vlinear(dp_xres + xoff, 95, 20);
172 if (UIButton(GEN_ID, vlinear, w, "Load...", ALIGN_RIGHT)) {
173 #if defined(USING_QT_UI) && defined(__SYMBIAN32__)
174 QString fileName = QFileDialog::getOpenFileName(NULL, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf)");
175 if (QFile::exists(fileName)) {
176 QDir newPath;
177 g_Config.currentDirectory = newPath.filePath(fileName).toStdString();
178 g_Config.Save();
179 screenManager()->switchScreen(new EmuScreen(fileName.toStdString()));
181 #else
182 FileSelectScreenOptions options;
183 options.allowChooseDirectory = true;
184 options.filter = "iso:cso:pbp:elf:prx:";
185 options.folderIcon = I_ICON_FOLDER;
186 options.iconMapping["iso"] = I_ICON_UMD;
187 options.iconMapping["cso"] = I_ICON_UMD;
188 options.iconMapping["pbp"] = I_ICON_EXE;
189 options.iconMapping["elf"] = I_ICON_EXE;
190 screenManager()->switchScreen(new FileSelectScreen(options));
191 #endif
192 UIReset();
195 if (UIButton(GEN_ID, vlinear, w, "Settings", ALIGN_RIGHT)) {
196 screenManager()->switchScreen(new SettingsScreen());
197 UIReset();
200 if (UIButton(GEN_ID, vlinear, w, "Credits", ALIGN_RIGHT)) {
201 screenManager()->switchScreen(new CreditsScreen());
202 UIReset();
205 if (UIButton(GEN_ID, vlinear, w, "Exit", ALIGN_RIGHT)) {
206 // TODO: Save when setting changes, rather than when we quit
207 NativeShutdown();
208 // TODO: Need a more elegant way to quit
209 exit(0);
212 if (UIButton(GEN_ID, vlinear, w, "www.ppsspp.org", ALIGN_RIGHT)) {
213 LaunchBrowser("http://www.ppsspp.org/");
216 DrawWatermark();
218 UIEnd();
220 glsl_bind(UIShader_Get());
221 ui_draw2d.Flush(UIShader_Get());
225 void InGameMenuScreen::update(InputState &input) {
226 if (input.pad_buttons_down & PAD_BUTTON_BACK) {
227 screenManager()->finishDialog(this, DR_CANCEL);
231 void InGameMenuScreen::render() {
232 UIShader_Prepare();
233 UIBegin();
234 DrawBackground(1.0f);
236 const char *title;
237 if (UTF8StringHasNonASCII(game_title.c_str())) {
238 title = "(can't display japanese title)";
239 } else {
240 title = game_title.c_str();
243 ui_draw2d.DrawText(UBUNTU48, title, dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER);
245 int x = 30;
246 int y = 50;
247 UICheckBox(GEN_ID, x, y += 50, "Show Debug Statistics", ALIGN_TOPLEFT, &g_Config.bShowDebugStats);
248 UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
250 // TODO: Add UI for more than one slot.
251 VLinear vlinear1(x, y + 80, 20);
252 UIText(UBUNTU24, vlinear1, "Save states are experimental (and large)", 0xFFFFFFFF);
253 if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Save State", ALIGN_LEFT)) {
254 SaveState::SaveSlot(0, 0, 0);
255 screenManager()->finishDialog(this, DR_CANCEL);
257 if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Load State", ALIGN_LEFT)) {
258 SaveState::LoadSlot(0, 0, 0);
259 screenManager()->finishDialog(this, DR_CANCEL);
262 VLinear vlinear(dp_xres - 10, 160, 20);
263 if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Continue", ALIGN_RIGHT)) {
264 screenManager()->finishDialog(this, DR_CANCEL);
266 if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Return to Menu", ALIGN_RIGHT)) {
267 screenManager()->finishDialog(this, DR_OK);
270 if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres - 10), LARGE_BUTTON_WIDTH*2, "Debug: Dump Next Frame", ALIGN_BOTTOMRIGHT)) {
271 gpu->DumpNextFrame();
274 DrawWatermark();
275 UIEnd();
277 glsl_bind(UIShader_Get());
278 ui_draw2d.Flush(UIShader_Get());
281 void SettingsScreen::update(InputState &input) {
282 if (input.pad_buttons_down & PAD_BUTTON_BACK) {
283 g_Config.Save();
284 screenManager()->switchScreen(new MenuScreen());
288 void SettingsScreen::render() {
289 UIShader_Prepare();
290 UIBegin();
291 DrawBackground(1.0f);
293 ui_draw2d.DrawText(UBUNTU48, "Settings", dp_xres / 2, 20, 0xFFFFFFFF, ALIGN_HCENTER);
295 // TODO: Need to add tabs soon...
296 // VLinear vlinear(10, 80, 10);
298 int x = 30;
299 int y = 30;
300 int stride = 40;
301 UICheckBox(GEN_ID, x, y += stride, "Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound);
302 UICheckBox(GEN_ID, x, y += stride, "Buffered Rendering", ALIGN_TOPLEFT, &g_Config.bBufferedRendering);
303 if (g_Config.bBufferedRendering) {
304 bool doubleRes = g_Config.iWindowZoom == 2;
305 UICheckBox(GEN_ID, x + 50, y += stride, "2x Render Resolution", ALIGN_TOPLEFT, &doubleRes);
306 g_Config.iWindowZoom = doubleRes ? 2 : 1;
308 UICheckBox(GEN_ID, x, y += stride, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
309 UICheckBox(GEN_ID, x, y += stride, "Draw using Stream VBO", ALIGN_TOPLEFT, &g_Config.bUseVBO);
310 UICheckBox(GEN_ID, x, y += stride, "Vertex Cache", ALIGN_TOPLEFT, &g_Config.bVertexCache);
312 bool useJit = g_Config.iCpuCore == CPU_JIT;
313 UICheckBox(GEN_ID, x, y += stride, "JIT (Dynarec)", ALIGN_TOPLEFT, &useJit);
314 if (g_Config.iCpuCore == CPU_JIT)
315 UICheckBox(GEN_ID, x + 450, y, "Fastmem (may crash)", ALIGN_TOPLEFT, &g_Config.bFastMemory);
316 g_Config.iCpuCore = useJit ? CPU_JIT : CPU_INTERPRETER;
317 // ui_draw2d.DrawText(UBUNTU48, "much faster JIT coming later", x, y+=50, 0xcFFFFFFF, ALIGN_LEFT);
318 UICheckBox(GEN_ID, x, y += stride, "On-screen Touch Controls", ALIGN_TOPLEFT, &g_Config.bShowTouchControls);
319 if (g_Config.bShowTouchControls) {
320 UICheckBox(GEN_ID, x + 450, y, "Large Controls", ALIGN_TOPLEFT, &g_Config.bLargeControls);
321 UICheckBox(GEN_ID, x + 50, y += stride, "Show Analog Stick", ALIGN_TOPLEFT, &g_Config.bShowAnalogStick);
323 // UICheckBox(GEN_ID, x, y += stride, "Draw raw framebuffer (for some homebrew)", ALIGN_TOPLEFT, &g_Config.bDisplayFramebuffer);
325 if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres-10), LARGE_BUTTON_WIDTH, "Back", ALIGN_RIGHT | ALIGN_BOTTOM)) {
326 screenManager()->switchScreen(new MenuScreen());
329 UIEnd();
331 glsl_bind(UIShader_Get());
332 ui_draw2d.Flush(UIShader_Get());
336 class FileListAdapter : public UIListAdapter {
337 public:
338 FileListAdapter(const FileSelectScreenOptions &options, const std::vector<FileInfo> *items) : options_(options), items_(items) {}
339 virtual size_t getCount() const { return items_->size(); }
340 virtual void drawItem(int item, int x, int y, int w, int h, bool active) const;
342 private:
343 const FileSelectScreenOptions &options_;
344 const std::vector<FileInfo> *items_;
347 void FileListAdapter::drawItem(int item, int x, int y, int w, int h, bool selected) const
349 int icon = -1;
350 if ((*items_)[item].isDirectory) {
351 icon = options_.folderIcon;
352 } else {
353 std::string extension = getFileExtension((*items_)[item].name);
354 auto iter = options_.iconMapping.find(extension);
355 if (iter != options_.iconMapping.end())
356 icon = iter->second;
358 int iconSpace = this->itemHeight(item);
359 ui_draw2d.DrawImage2GridH(selected ? I_BUTTON_SELECTED: I_BUTTON, x, y, x + w);
360 ui_draw2d.DrawTextShadow(UBUNTU24, (*items_)[item].name.c_str(), x + UI_SPACE + iconSpace, y + 25, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER);
361 if (icon != -1)
362 ui_draw2d.DrawImage(icon, x + UI_SPACE, y + 25, 1.0f, 0xFFFFFFFF, ALIGN_VCENTER | ALIGN_LEFT);
366 FileSelectScreen::FileSelectScreen(const FileSelectScreenOptions &options) : options_(options) {
367 currentDirectory_ = g_Config.currentDirectory;
368 updateListing();
371 void FileSelectScreen::updateListing() {
372 listing_.clear();
373 getFilesInDir(currentDirectory_.c_str(), &listing_, options_.filter);
374 g_Config.currentDirectory = currentDirectory_;
375 list_.contentChanged();
378 void FileSelectScreen::update(InputState &input_state) {
379 if (input_state.pad_buttons_down & PAD_BUTTON_BACK) {
380 g_Config.Save();
381 screenManager()->switchScreen(new MenuScreen());
385 void FileSelectScreen::render() {
386 FileListAdapter adapter(options_, &listing_);
388 UIShader_Prepare();
389 UIBegin();
390 DrawBackground(1.0f);
392 if (list_.Do(GEN_ID, 10, BUTTON_HEIGHT + 20, dp_xres-20, dp_yres - BUTTON_HEIGHT - 30, &adapter)) {
393 if (listing_[list_.selected].isDirectory) {
394 currentDirectory_ = listing_[list_.selected].fullName;
395 ILOG("%s", currentDirectory_.c_str());
396 updateListing();
397 list_.selected = -1;
398 } else {
399 std::string boot_filename = listing_[list_.selected].fullName;
400 ILOG("Selected: %i : %s", list_.selected, boot_filename.c_str());
401 list_.selected = -1;
402 g_Config.Save();
404 screenManager()->switchScreen(new EmuScreen(boot_filename));
408 ui_draw2d.DrawImageStretch(I_BUTTON, 0, 0, dp_xres, 70);
410 if (UIButton(GEN_ID, Pos(10,10), SMALL_BUTTON_WIDTH, "Up", ALIGN_TOPLEFT)) {
411 currentDirectory_ = getDir(currentDirectory_);
412 updateListing();
414 ui_draw2d.DrawTextShadow(UBUNTU24, currentDirectory_.c_str(), 20 + SMALL_BUTTON_WIDTH, 10 + 25, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER);
417 if (UIButton(GEN_ID, Pos(dp_xres - 10, 10), SMALL_BUTTON_WIDTH, "Back", ALIGN_RIGHT)) {
418 g_Config.Save();
419 screenManager()->switchScreen(new MenuScreen());
421 UIEnd();
423 glsl_bind(UIShader_Get());
424 ui_draw2d.Flush(UIShader_Get());
427 void CreditsScreen::update(InputState &input_state) {
428 if (input_state.pad_buttons_down & PAD_BUTTON_BACK) {
429 screenManager()->switchScreen(new MenuScreen());
431 frames_++;
434 static const char *credits[] =
436 "PPSSPP " PPSSPP_VERSION_STR,
439 "A fast and portable PSP emulator",
440 "(well, an early prototype of that)",
442 "Created by Henrik Rydgard",
444 "Contributors:",
445 "unknownbrackets",
446 "orphis",
447 "xsacha",
448 "artart78",
449 "tmaul",
450 "ced2911",
451 "soywiz",
452 "kovensky",
453 "raven02",
455 "Written in C++ for speed and portability",
458 "Free tools used:",
459 #ifdef ANDROID
460 "Android SDK + NDK",
461 #elif defined(BLACKBERRY)
462 "Blackberry NDK",
463 #elif defined(USING_QT_UI)
464 "Qt",
465 #else
466 "SDL",
467 #endif
468 "CMake",
469 "freetype2",
470 "zlib",
471 "PSP SDK",
474 "Check out the website:",
475 "www.ppsspp.org",
476 "compatibility lists, forums, and development info",
479 "Also check out Dolphin, the best Wii/GC emu around:",
480 "http://www.dolphin-emu.org",
483 "PPSSPP is intended for educational purposes only.",
485 "Please make sure that you own the rights to any games",
486 "you play by owning the UMD or buying the digital",
487 "download from the PSN store on your real PSP.",
490 "PSP is a trademark by Sony, Inc.",
493 void CreditsScreen::render() {
494 UIShader_Prepare();
495 UIBegin();
496 DrawBackground(1.0f);
498 const int numItems = ARRAY_SIZE(credits);
499 int itemHeight = 36;
500 int totalHeight = numItems * itemHeight + dp_yres + 200;
501 int y = dp_yres - (frames_ % totalHeight);
502 for (int i = 0; i < numItems; i++) {
503 float alpha = linearInOut(y+32, 64, dp_yres - 192, 64);
504 if (alpha > 0.0f) {
505 UIText(dp_xres/2, y, credits[i], whiteAlpha(alpha), ease(alpha), ALIGN_HCENTER);
507 y += itemHeight;
510 if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres - 10), 200, "Back", ALIGN_BOTTOMRIGHT)) {
511 screenManager()->switchScreen(new MenuScreen());
514 UIEnd();
516 glsl_bind(UIShader_Get());
517 ui_draw2d.Flush(UIShader_Get());
520 void ErrorScreen::update(InputState &input_state) {
521 if (input_state.pad_buttons_down & PAD_BUTTON_BACK) {
522 screenManager()->finishDialog(this, DR_OK);
526 void ErrorScreen::render()
528 UIShader_Prepare();
529 UIBegin();
530 DrawBackground(1.0f);
532 ui_draw2d.DrawText(UBUNTU48, errorTitle_.c_str(), dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER);
533 ui_draw2d.DrawText(UBUNTU24, errorMessage_.c_str(), 40, 120, 0xFFFFFFFF, ALIGN_LEFT);
535 if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres - 10), 200, "Back", ALIGN_BOTTOMRIGHT)) {
536 screenManager()->finishDialog(this, DR_OK);
539 UIEnd();
541 glsl_bind(UIShader_Get());
542 ui_draw2d.Flush(UIShader_Get());