diff --git a/.travis.yml b/.travis.yml index 82072d146a..6cd994d026 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ matrix: - clang-3.8 env: COMPILER_NAME=clang-3.8 CXX=clang++-3.8 CC=clang-3.8 - os: osx - osx_image: xcode7.3 + osx_image: xcode8 script: - xcodebuild -target RetroArch -configuration Release -project pkg/apple/RetroArch.xcodeproj - os: osx diff --git a/.vscode/settings.json b/.vscode/settings.json index d445ffca01..c44832dca4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,7 +33,14 @@ "hash_set": "c", "initializer_list": "c", "string_view": "c", - "utility": "c" + "utility": "c", + "menu_input.h": "c", + "tasks_internal.h": "c", + "ozone.h": "c", + "ozone_theme.h": "c", + "ozone_texture.h": "c", + "string_list.h": "c", + "core_info.h": "c" }, "C_Cpp.dimInactiveRegions": false, } \ No newline at end of file diff --git a/10bpc-gl.diff b/10bpc-gl.diff new file mode 100644 index 0000000000..9436f12f82 --- /dev/null +++ b/10bpc-gl.diff @@ -0,0 +1,96 @@ +diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c +index b90a8e40c3..e57c4df194 100644 +--- a/gfx/drivers_context/wgl_ctx.c ++++ b/gfx/drivers_context/wgl_ctx.c +@@ -78,6 +78,47 @@ + #ifndef WGL_CONTEXT_DEBUG_BIT_ARB + #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 + #endif ++ ++#ifndef WGL_ACCELERATION_ARB ++#define WGL_ACCELERATION_ARB 0x2003 ++#endif ++ ++#ifndef WGL_FULL_ACCELERATION_ARB ++#define WGL_FULL_ACCELERATION_ARB 0x2027 ++#endif ++ ++#ifndef WGL_DRAW_TO_WINDOW_ARB ++#define WGL_DRAW_TO_WINDOW_ARB 0x2001 ++#endif ++ ++#ifndef WGL_DOUBLE_BUFFER_ARB ++#define WGL_DOUBLE_BUFFER_ARB 0x2011 ++#endif ++ ++#ifndef WGL_RED_BITS_ARB ++#define WGL_RED_BITS_ARB 0x2015 ++#endif ++ ++#ifndef WGL_GREEN_BITS_ARB ++#define WGL_GREEN_BITS_ARB 0x2017 ++#endif ++ ++#ifndef WGL_BLUE_BITS_ARB ++#define WGL_BLUE_BITS_ARB 0x2019 ++#endif ++ ++#ifndef WGL_ALPHA_BITS_ARB ++#define WGL_ALPHA_BITS_ARB 0x201B ++#endif ++ ++#ifndef WGL_PIXEL_TYPE_ARB ++#define WGL_PIXEL_TYPE_ARB 0x2013 ++#endif ++ ++#ifndef WGL_TYPE_RGBA_ARB ++#define WGL_TYPE_RGBA_ARB 0x202B ++#endif ++ + #endif + + #if defined(HAVE_OPENGL) +@@ -313,6 +354,43 @@ static void create_gl_context(HWND hwnd, bool *quit) + RARCH_LOG("[WGL]: Adaptive VSync supported.\n"); + wgl_adaptive_vsync = true; + } ++ if (wgl_has_extension("WGL_ARB_pixel_format", extensions)) ++ { ++ BOOL (WINAPI * wglChoosePixelFormatARB) ++ (HDC hdc, ++ const int *piAttribIList, ++ const FLOAT *pfAttribFList, ++ UINT nMaxFormats, ++ int *piFormats, ++ UINT *nNumFormats); ++ UINT nMatchingFormats; ++ int index = 0; ++ int attribsDesired[] = { ++ WGL_DRAW_TO_WINDOW_ARB, 1, ++ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, ++ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, ++ WGL_RED_BITS_ARB, 10, ++ WGL_GREEN_BITS_ARB, 10, ++ WGL_BLUE_BITS_ARB, 10, ++ WGL_ALPHA_BITS_ARB, 2, ++ WGL_DOUBLE_BUFFER_ARB, 1, ++ 0,0 ++ }; ++ wglChoosePixelFormatARB = (BOOL (WINAPI *) (HDC, const int *, ++ const FLOAT*, UINT, int*, UINT*)) ++ gfx_ctx_wgl_get_proc_address("wglChoosePixelFormatARB"); ++ ++ RARCH_LOG("[WGL]: ARB pixel format supported.\n"); ++ ++ if (wglChoosePixelFormatARB(win32_hdc, attribsDesired, ++ NULL, 1, &index, &nMatchingFormats)) ++ { ++ if (nMatchingFormats == 0) ++ { ++ RARCH_WARN("No 10bpc WGL_ARB_pixel_formats found!\n"); ++ } ++ } ++ } + } + } + #endif diff --git a/Makefile.common b/Makefile.common index 0554d01f7f..72f88223ea 100644 --- a/Makefile.common +++ b/Makefile.common @@ -716,7 +716,12 @@ ifeq ($(HAVE_XMB), 1) endif ifeq ($(HAVE_OZONE), 1) - OBJ += menu/drivers/ozone.o + OBJ += menu/drivers/ozone/ozone.o + OBJ += menu/drivers/ozone/ozone_entries.o + OBJ += menu/drivers/ozone/ozone_display.o + OBJ += menu/drivers/ozone/ozone_texture.o + OBJ += menu/drivers/ozone/ozone_theme.o + OBJ += menu/drivers/ozone/ozone_sidebar.o DEFINES += -DHAVE_OZONE HAVE_MENU_COMMON = 1 endif diff --git a/Makefile.libnx b/Makefile.libnx index 689d8f6d47..b9f482b563 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -222,7 +222,8 @@ ifneq ($(ROMFS),) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) endif -DEPENDS := $(OFILES:.o=.d) +DEPENDS_TMP := $(OFILES:.o=.d) +DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP)) .PHONY: clean all @@ -244,7 +245,7 @@ endif $(OUTPUT).elf : $(OBJ) clean: - rm -f $(OBJ) $(OUTPUT).pfs0 $(OUTPUT).nro $(OUTPUT).elf + rm -f $(DEPENDS) $(OBJ) $(OUTPUT).pfs0 $(OUTPUT).nro $(OUTPUT).elf #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data diff --git a/README.md b/README.md index 1e4105cc53..c7fcf261c5 100644 --- a/README.md +++ b/README.md @@ -189,46 +189,46 @@ The default super resolution is 2560. It is displayed just under the CRT switch If native resolutions are activated you will need a whole new set of modelines: -- 512 x 240 @ 50.006977 SNESpal +- 256 x 240 @ 50.006977 SNESpal +- 256 x 448 @ 50.006977 SNESpal - 512 x 224 @ 50.006977 SNESpal +- 512 x 240 @ 50.006977 SNESpal - 512 x 448 @ 50.006977 SNESpal +- 256 x 240 @ 60.098812 SNESntsc +- 256 x 448 @ 60.098812 SNESntsc - 512 x 240 @ 60.098812 SNESntsc - 512 x 224 @ 60.098812 SNESntsc - 512 x 448 @ 60.098812 SNESntsc -- 256 x 240 @ 50.006977 SNESpal -- 256 x 448 @ 50.006977 SNESpal -- 256 x 240 @ 60.098812 SNESntsc -- 256 x 448 @ 60.098812 SNESntsc -- 320 x 240 @ 59.922745 MDntsc -- 320 x 448 @ 59.922745 MDntp -- 320 x 480 @ 59.922745 MDntsc - 256 x 192 @ 59.922745 MDntsc -- 320 x 224 @ 59.922745 MDntsc - 256 x 224 @ 59.922745 MDntsc -- 320 x 288 @ 49.701458 MDpal -- 320 x 576 @ 49.701458 MDpal +- 320 x 224 @ 59.922745 MDntsc +- 320 x 240 @ 59.922745 MDntsc +- 320 x 448 @ 59.922745 MDntsc +- 320 x 480 @ 59.922745 MDntsc - 256 x 192 @ 49.701458 MDpal +- 256 x 224 @ 49.701458 MDpal - 320 x 224 @ 49.701458 MDpal - 320 x 240 @ 49.701458 MDpal +- 320 x 288 @ 49.701458 MDpal - 320 x 448 @ 49.701458 MDpal - 320 x 480 @ 49.701458 MDpal -- 256 x 224 @ 49.701458 MDpal +- 320 x 576 @ 49.701458 MDpal - 256 x 288 @ 49.701458 MSYSpal - 256 x 240 @ 60.098812 NESntsc - 256 x 240 @ 50.006977 NESpal -- 640 x 480 @ 60.130001 N64ntsc - 640 x 237 @ 60.130001 N64ntsc - 640 x 240 @ 60.130001 N64ntsc +- 640 x 480 @ 60.130001 N64ntsc +- 640 x 288 @ 50.000000 N64pal - 640 x 480 @ 50.000000 N64pal -- 640 x 576 @ 50.000000 n64pal -- 640 x 288 @ 50.000000 n64pal +- 640 x 576 @ 50.000000 N64pal - 256 x 252 @ 49.759998 PSXpal -- 384 x 252 @ 49.759998 PSXpal -- 640 x 540 @ 49.759998 PSXpal - 320 x 252 @ 49.759998 PSXpal +- 384 x 252 @ 49.759998 PSXpal - 640 x 252 @ 49.759998 PSXpal +- 640 x 540 @ 49.759998 PSXpal - 384 x 240 @ 59.941002 PSXntsc - 256 x 480 @ 59.941002 PSXntsc diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c index 593a377082..d711fd7141 100644 --- a/audio/drivers/wasapi.c +++ b/audio/drivers/wasapi.c @@ -29,6 +29,19 @@ #include #include +#ifdef _MSC_VER +/* IID_IAudioClient 1CB9AD4C-DBFA-4c32-B178-C2F568A703B2 */ +static const GUID IID_IAudioClient = { 0x1CB9AD4C, 0xDBFA, 0xB178, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2 }; +/* IID_IAudioRenderClient F294ACFC-3146-4483-A7BF-ADDCA7C260E2 */ +static const GUID IID_IAudioRenderClient = { 0xF294ACFC, 0x3146, 0x4483, 0xA7BF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2 }; +/* IID_IMMDeviceEnumerator A95664D2-9614-4F35-A746-DE8DB63617E6 */ +static const GUID IID_IMMDeviceEnumerator = { 0xA95664D2, 0x9614, 0x4F35, 0xA746, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6 }; +/* CLSID_MMDeviceEnumerator BCDE0395-E52F-467C-8E3D-C4579291692E */ +static const GUID CLSID_MMDeviceEnumerator = { 0xBCDE0395, 0xE52F, 0x467C, 0x8E3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E }; +/* KSDATAFORMAT_SUBTYPE_IEEE_FLOAT 00000003-0000-0010-8000-00aa00389b71 */ +static const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, 0x8000, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; +#endif + #include #include diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index 3539db7938..78d7d0d6ab 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -1745,7 +1745,7 @@ found: settings_t *settings = config_get_ptr(); if (!( string_is_equal(settings->arrays.menu_driver, "xmb") || - !string_is_equal(settings->arrays.menu_driver, "ozone") + string_is_equal(settings->arrays.menu_driver, "ozone") ) || !settings->bools.cheevos_badges_enable) CORO_RET(); diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 134e7e6513..c4f637255f 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1,3738 +1,3738 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2018 - Andre Leiradella - * - * RetroArch 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 Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch 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 RetroArch. - * If not, see . - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_MENU -#include "../menu/menu_driver.h" -#include "../menu/menu_entries.h" -#endif - -#ifdef HAVE_THREADS -#include -#endif - -#include "badges.h" -#include "cheevos.h" -#include "var.h" -#include "cond.h" - -#include "../file_path_special.h" -#include "../paths.h" -#include "../command.h" -#include "../dynamic.h" -#include "../configuration.h" -#include "../performance_counters.h" -#include "../msg_hash.h" -#include "../retroarch.h" -#include "../core.h" - -#include "../network/net_http_special.h" -#include "../tasks/tasks_internal.h" - -#include "../verbosity.h" - -/* Define this macro to prevent cheevos from being deactivated. */ -#undef CHEEVOS_DONT_DEACTIVATE - -/* Define this macro to log URLs (will log the user token). */ -#undef CHEEVOS_LOG_URLS - -/* Define this macro to dump all cheevos' addresses. */ -#undef CHEEVOS_DUMP_ADDRS - -/* Define this macro to remove HTTP timeouts. */ -#undef CHEEVOS_NO_TIMEOUT - -/* Define this macro to load a JSON file from disk instead of downloading - * from retroachievements.org. */ -#undef CHEEVOS_JSON_OVERRIDE - -/* Define this macro with a string to save the JSON file to disk with - * that name. */ -#undef CHEEVOS_SAVE_JSON - -/* Define this macro to have the password and token logged. THIS WILL DISCLOSE - * THE USER'S PASSWORD, TAKE CARE! */ -#undef CHEEVOS_LOG_PASSWORD - -/* Define this macro to log downloaded badge images. */ -#undef CHEEVOS_LOG_BADGES - -/* C89 wants only int values in enums. */ -#define CHEEVOS_JSON_KEY_GAMEID 0xb4960eecU -#define CHEEVOS_JSON_KEY_ACHIEVEMENTS 0x69749ae1U -#define CHEEVOS_JSON_KEY_ID 0x005973f2U -#define CHEEVOS_JSON_KEY_MEMADDR 0x1e76b53fU -#define CHEEVOS_JSON_KEY_TITLE 0x0e2a9a07U -#define CHEEVOS_JSON_KEY_DESCRIPTION 0xe61a1f69U -#define CHEEVOS_JSON_KEY_POINTS 0xca8fce22U -#define CHEEVOS_JSON_KEY_AUTHOR 0xa804edb8U -#define CHEEVOS_JSON_KEY_MODIFIED 0xdcea4fe6U -#define CHEEVOS_JSON_KEY_CREATED 0x3a84721dU -#define CHEEVOS_JSON_KEY_BADGENAME 0x887685d9U -#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U -#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U -#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U -#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU -#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U -#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU -#define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU -#define CHEEVOS_JSON_KEY_ERROR 0x0d2011cfU - -typedef struct -{ - cheevos_cond_t *conds; - unsigned count; -} cheevos_condset_t; - -typedef struct -{ - cheevos_condset_t *condsets; - unsigned count; -} cheevos_condition_t; - -typedef struct -{ - unsigned id; - const char *title; - const char *description; - const char *author; - const char *badge; - unsigned points; - unsigned dirty; - int active; - int last; - int modified; - - cheevos_condition_t condition; -} cheevo_t; - -typedef struct -{ - cheevo_t *cheevos; - unsigned count; -} cheevoset_t; - -typedef struct -{ - int is_element; - int mode; -} cheevos_deactivate_t; - -typedef struct -{ - unsigned key_hash; - int is_key; - const char *value; - size_t length; -} cheevos_getvalueud_t; - -typedef struct -{ - int in_cheevos; - int in_lboards; - uint32_t field_hash; - unsigned core_count; - unsigned unofficial_count; - unsigned lboard_count; -} cheevos_countud_t; - -typedef struct -{ - const char *string; - size_t length; -} cheevos_field_t; - -typedef struct -{ - int in_cheevos; - int in_lboards; - int is_console_id; - unsigned core_count; - unsigned unofficial_count; - unsigned lboard_count; - - cheevos_field_t *field; - cheevos_field_t id, memaddr, title, desc, points, author; - cheevos_field_t modified, created, badge, flags, format; -} cheevos_readud_t; - -typedef struct -{ - int label; - const char *name; - const uint32_t *ext_hashes; -} cheevos_finder_t; - -typedef struct -{ - cheevos_var_t var; - double multiplier; - bool compare_next; -} cheevos_term_t; - -typedef struct -{ - cheevos_term_t *terms; - unsigned count; - unsigned compare_count; -} cheevos_expr_t; - -typedef struct -{ - unsigned id; - unsigned format; - const char *title; - const char *description; - int active; - int last_value; - - cheevos_condition_t start; - cheevos_condition_t cancel; - cheevos_condition_t submit; - cheevos_expr_t value; -} cheevos_leaderboard_t; - -typedef struct -{ - retro_task_t* task; -#ifdef HAVE_THREADS - slock_t* task_lock; -#endif - - cheevos_console_t console_id; - bool core_supports; - bool addrs_patched; - int add_buffer; - int add_hits; - - cheevoset_t core; - cheevoset_t unofficial; - cheevos_leaderboard_t *leaderboards; - unsigned lboard_count; - - char token[32]; - - retro_ctx_memory_info_t meminfo[4]; -} cheevos_locals_t; - -typedef struct -{ - uint8_t id[4]; /* NES^Z */ - uint8_t rom_size; - uint8_t vrom_size; - uint8_t rom_type; - uint8_t rom_type2; - uint8_t reserve[8]; -} cheevos_nes_header_t; - -static cheevos_locals_t cheevos_locals = -{ - /* task */ NULL, -#ifdef HAVE_THREADS - /* task_lock */ NULL, -#endif - - /* console_id */ CHEEVOS_CONSOLE_NONE, - /* core_supports */ true, - /* addrs_patched */ false, - /* add_buffer */ 0, - /* add_hits */ 0, - - /* core */ {NULL, 0}, - /* unofficial */ {NULL, 0}, - /* leaderboards */ NULL, - /* lboard_count */ 0, - - /* token */ {0}, - - { - /* meminfo[0] */ {NULL, 0, 0}, - /* meminfo[1] */ {NULL, 0, 0}, - /* meminfo[2] */ {NULL, 0, 0}, - /* meminfo[3] */ {NULL, 0, 0} - } -}; - -bool cheevos_loaded = false; -bool cheevos_hardcore_active = false; -bool cheevos_hardcore_paused = false; -bool cheevos_state_loaded_flag = false; -int cheats_are_enabled = 0; -int cheats_were_enabled = 0; - -#ifdef HAVE_THREADS -#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0) -#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0) -#else -#define CHEEVOS_LOCK(l) -#define CHEEVOS_UNLOCK(l) -#endif - -/***************************************************************************** -Supporting functions. -*****************************************************************************/ - -#ifndef CHEEVOS_VERBOSE - -void cheevos_log(const char *fmt, ...) -{ - (void)fmt; -} - -#endif - -static unsigned size_in_megabytes(unsigned val) -{ - return (val * 1024 * 1024); -} - -#ifdef CHEEVOS_LOG_URLS -static void cheevos_log_url(const char* format, const char* url) -{ -#ifdef CHEEVOS_LOG_PASSWORD - CHEEVOS_LOG(format, url); -#else - char copy[256]; - char* aux = NULL; - char* next = NULL; - - if (!string_is_empty(url)) - strlcpy(copy, url, sizeof(copy)); - - aux = strstr(copy, "?p="); - - if (!aux) - aux = strstr(copy, "&p="); - - if (aux) - { - aux += 3; - next = strchr(aux, '&'); - - if (next) - { - do - { - *aux++ = *next++; - }while (next[-1] != 0); - } - else - *aux = 0; - } - - aux = strstr(copy, "?t="); - - if (!aux) - aux = strstr(copy, "&t="); - - if (aux) - { - aux += 3; - next = strchr(aux, '&'); - - if (next) - { - do - { - *aux++ = *next++; - }while (next[-1] != 0); - } - else - *aux = 0; - } - - CHEEVOS_LOG(format, copy); -#endif -} -#endif - -static uint32_t cheevos_djb2(const char* str, size_t length) -{ - const unsigned char *aux = (const unsigned char*)str; - const unsigned char *end = aux + length; - uint32_t hash = 5381; - - while (aux < end) - hash = (hash << 5) + hash + *aux++; - - return hash; -} - -static int cheevos_getvalue__json_key(void *userdata, - const char *name, size_t length) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud) - ud->is_key = cheevos_djb2(name, length) == ud->key_hash; - return 0; -} - -static int cheevos_getvalue__json_string(void *userdata, - const char *string, size_t length) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key) - { - ud->value = string; - ud->length = length; - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_getvalue__json_boolean(void *userdata, int istrue) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key) - { - if (istrue) - { - ud->value = "true"; - ud->length = 4; - } - else - { - ud->value = "false"; - ud->length = 5; - } - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_getvalue__json_null(void *userdata) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key ) - { - ud->value = "null"; - ud->length = 4; - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_get_value(const char *json, unsigned key_hash, - char *value, size_t length) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_getvalue__json_key, - NULL, - cheevos_getvalue__json_string, - cheevos_getvalue__json_string, /* number */ - cheevos_getvalue__json_boolean, - cheevos_getvalue__json_null - }; - - cheevos_getvalueud_t ud; - - ud.key_hash = key_hash; - ud.is_key = 0; - ud.value = NULL; - ud.length = 0; - *value = 0; - - if ((jsonsax_parse(json, &handlers, (void*)&ud) == JSONSAX_OK) - && ud.value && ud.length < length) - { - if (!string_is_empty(ud.value)) - strlcpy(value, ud.value, ud.length + 1); - return 0; - } - - return -1; -} - -/***************************************************************************** -Count number of achievements in a JSON file. -*****************************************************************************/ - -static int cheevos_count__json_end_array(void *userdata) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - ud->in_cheevos = 0; - ud->in_lboards = 0; - } - - return 0; -} - -static int cheevos_count__json_key(void *userdata, - const char *name, size_t length) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - ud->field_hash = cheevos_djb2(name, length); - if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS) - ud->in_cheevos = 1; - else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS) - ud->in_lboards = 1; - } - - return 0; -} - -static int cheevos_count__json_number(void *userdata, - const char *number, size_t length) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - if (ud->in_cheevos && ud->field_hash == CHEEVOS_JSON_KEY_FLAGS) - { - long flags = strtol(number, NULL, 10); - - if (flags == 3) - ud->core_count++; /* Core achievements */ - else if (flags == 5) - ud->unofficial_count++; /* Unofficial achievements */ - } - else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID) - ud->lboard_count++; - } - - return 0; -} - -static int cheevos_count_cheevos(const char *json, - unsigned *core_count, unsigned *unofficial_count, - unsigned *lboard_count) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_count__json_end_array, - cheevos_count__json_key, - NULL, - NULL, - cheevos_count__json_number, - NULL, - NULL - }; - - int res; - cheevos_countud_t ud; - ud.in_cheevos = 0; - ud.in_lboards = 0; - ud.core_count = 0; - ud.unofficial_count = 0; - ud.lboard_count = 0; - - res = jsonsax_parse(json, &handlers, (void*)&ud); - - *core_count = ud.core_count; - *unofficial_count = ud.unofficial_count; - *lboard_count = ud.lboard_count; - - return res; -} - -/***************************************************************************** -Parse the MemAddr field. -*****************************************************************************/ - -static unsigned cheevos_count_cond_sets(const char *memaddr) -{ - cheevos_cond_t cond; - unsigned count = 0; - - for (;;) - { - count++; - - for (;;) - { - cheevos_cond_parse(&cond, &memaddr); - - if (*memaddr != '_') - break; - - memaddr++; - } - - if (*memaddr != 'S') - break; - - memaddr++; - } - - return count; -} - -static int cheevos_parse_condition( - cheevos_condition_t *condition, - const char* memaddr) -{ - if (!condition) - return 0; - - condition->count = cheevos_count_cond_sets(memaddr); - - if (condition->count) - { - unsigned set = 0; - const cheevos_condset_t* end = NULL; - cheevos_condset_t *conds = NULL; - cheevos_condset_t *condset = NULL; - cheevos_condset_t *condsets = (cheevos_condset_t*) - calloc(condition->count, sizeof(cheevos_condset_t)); - - (void)conds; - - if (!condsets) - return -1; - - condition->condsets = condsets; - end = condition->condsets + condition->count; - - for (condset = condition->condsets; condset < end; condset++, set++) - { - condset->count = - cheevos_cond_count_in_set(memaddr, set); - condset->conds = NULL; - - CHEEVOS_LOG("[CHEEVOS]: set %p (index=%u)\n", condset, set); - CHEEVOS_LOG("[CHEEVOS]: conds: %u\n", condset->count); - - if (condset->count) - { - cheevos_cond_t *conds = (cheevos_cond_t*) - calloc(condset->count, sizeof(cheevos_cond_t)); - - if (!conds) - { - while (--condset >= condition->condsets) - { - if ((void*)condset->conds) - free((void*)condset->conds); - } - - return -1; - } - - condset->conds = conds; - cheevos_cond_parse_in_set(condset->conds, memaddr, set); - } - } - } - - return 0; -} - -static void cheevos_free_condition(cheevos_condition_t* condition) -{ - unsigned i; - - if (!condition) - return; - - if (condition->condsets) - { - for (i = 0; i < condition->count; i++) - { - if (condition->condsets[i].conds) - { - free(condition->condsets[i].conds); - condition->condsets[i].conds = NULL; - } - } - - if (condition->condsets) - { - free(condition->condsets); - condition->condsets = NULL; - } - } -} - -/***************************************************************************** -Parse the Mem field of leaderboards. -*****************************************************************************/ - -static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem) -{ - unsigned i; - const char *aux; - cheevos_term_t *terms = NULL; - char *end = NULL; - - if (!expr) - return -1; - - expr->count = 1; - expr->compare_count = 1; - - for (aux = mem;; aux++) - { - if (*aux == '"' || *aux == ':') - break; - expr->count += *aux == '_'; - } - - if (expr->count > 0) - terms = (cheevos_term_t*) - calloc(expr->count, sizeof(cheevos_term_t)); - - if (!terms) - return -1; - - expr->terms = terms; - - for (i = 0; i < expr->count; i++) - { - expr->terms[i].compare_next = false; - expr->terms[i].multiplier = 1; - } - - for (i = 0, aux = mem; i < expr->count;) - { - cheevos_var_parse(&expr->terms[i].var, &aux); - - if (*aux != '*') - { - /* expression has no multiplier */ - if (*aux == '_') - { - aux++; - i++; - } - else if (*aux == '$') - { - expr->terms[i].compare_next = true; - expr->compare_count++; - aux++; - i++; - } - - /* no multiplier at end of string */ - else if (*aux == '\0' || *aux == '"' || *aux == ',') - return 0; - - /* invalid character in expression */ - else - { - if (expr->terms) - { - free(expr->terms); - expr->terms = NULL; - } - return -1; - } - } - else - { - if (aux[1] == 'h' || aux[1] == 'H') - expr->terms[i].multiplier = (double)strtol(aux + 2, &end, 16); - else - expr->terms[i].multiplier = strtod(aux + 1, &end); - aux = end; - - if (*aux == '$') - { - aux++; - expr->terms[i].compare_next = true; - expr->compare_count++; - } - else - expr->terms[i].compare_next = false; - - aux++; - i++; - } - } - return 0; -} - -static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem) -{ - lb->start.condsets = NULL; - lb->cancel.condsets = NULL; - lb->submit.condsets = NULL; - lb->value.terms = NULL; - - for (;;) - { - if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->start, mem + 4)) - goto error; - } - else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->cancel, mem + 4)) - goto error; - } - else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->submit, mem + 4)) - goto error; - } - else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':') - { - if (cheevos_parse_expression(&lb->value, mem + 4)) - goto error; - } - - for (mem += 4;; mem++) - { - if (*mem == ':' && mem[1] == ':') - { - mem += 2; - break; - } - else if (*mem == '"') - return 0; - } - } - -error: - cheevos_free_condition(&lb->start); - cheevos_free_condition(&lb->cancel); - cheevos_free_condition(&lb->submit); - if (lb->value.terms) - { - free((void*)lb->value.terms); - lb->value.terms = NULL; - } - return -1; -} - -/***************************************************************************** -Load achievements from a JSON string. -*****************************************************************************/ - -static INLINE const char *cheevos_dupstr(const cheevos_field_t *field) -{ - char *string = (char*)malloc(field->length + 1); - - if (!string) - return NULL; - - memcpy ((void*)string, (void*)field->string, field->length); - string[field->length] = 0; - - return string; -} - -static int cheevos_new_cheevo(cheevos_readud_t *ud) -{ - cheevo_t *cheevo = NULL; - long flags = strtol(ud->flags.string, NULL, 10); - - if (flags == 3) - cheevo = cheevos_locals.core.cheevos + ud->core_count++; - else if (flags == 5) - cheevo = cheevos_locals.unofficial.cheevos + ud->unofficial_count++; - else - return 0; - - cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10); - cheevo->title = cheevos_dupstr(&ud->title); - cheevo->description = cheevos_dupstr(&ud->desc); - cheevo->author = cheevos_dupstr(&ud->author); - cheevo->badge = cheevos_dupstr(&ud->badge); - cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10); - cheevo->dirty = 0; - cheevo->active = CHEEVOS_ACTIVE_SOFTCORE | CHEEVOS_ACTIVE_HARDCORE; - cheevo->last = 1; - cheevo->modified = 0; - - if ( !cheevo->title || - !cheevo->description || - !cheevo->author || - !cheevo->badge) - goto error; - - if (cheevos_parse_condition(&cheevo->condition, ud->memaddr.string)) - goto error; - - return 0; - -error: - if (cheevo->title) - { - free((void*)cheevo->title); - cheevo->title = NULL; - } - if (cheevo->description) - { - free((void*)cheevo->description); - cheevo->description = NULL; - } - if (cheevo->author) - { - free((void*)cheevo->author); - cheevo->author = NULL; - } - if (cheevo->badge) - { - free((void*)cheevo->badge); - cheevo->badge = NULL; - } - return -1; -} - -/***************************************************************************** -Helper functions for displaying leaderboard values. -*****************************************************************************/ - -static void cheevos_format_value(const unsigned value, const unsigned type, - char* formatted_value, size_t formatted_size) -{ - unsigned mins, secs, millis; - - switch(type) - { - case CHEEVOS_FORMAT_VALUE: - snprintf(formatted_value, formatted_size, "%u", value); - break; - - case CHEEVOS_FORMAT_SCORE: - snprintf(formatted_value, formatted_size, - "%06upts", value); - break; - - case CHEEVOS_FORMAT_FRAMES: - mins = value / 3600; - secs = (value % 3600) / 60; - millis = (int) (value % 60) * (10.00 / 6.00); - snprintf(formatted_value, formatted_size, - "%02u:%02u.%02u", mins, secs, millis); - break; - - case CHEEVOS_FORMAT_MILLIS: - mins = value / 6000; - secs = (value % 6000) / 100; - millis = (int) (value % 100); - snprintf(formatted_value, formatted_size, - "%02u:%02u.%02u", mins, secs, millis); - break; - - case CHEEVOS_FORMAT_SECS: - mins = value / 60; - secs = value % 60; - snprintf(formatted_value, formatted_size, - "%02u:%02u", mins, secs); - break; - - default: - snprintf(formatted_value, formatted_size, - "%u (?)", value); - } -} - -unsigned cheevos_parse_format(cheevos_field_t* format) -{ - /* Most likely */ - if (strncmp(format->string, "VALUE", format->length) == 0) - return CHEEVOS_FORMAT_VALUE; - else if (strncmp(format->string, "TIME", format->length) == 0) - return CHEEVOS_FORMAT_FRAMES; - else if (strncmp(format->string, "SCORE", format->length) == 0) - return CHEEVOS_FORMAT_SCORE; - - /* Less likely */ - else if (strncmp(format->string, "MILLISECS", format->length) == 0) - return CHEEVOS_FORMAT_MILLIS; - else if (strncmp(format->string, "TIMESECS", format->length) == 0) - return CHEEVOS_FORMAT_SECS; - - /* Rare (RPS only) */ - else if (strncmp(format->string, "POINTS", format->length) == 0) - return CHEEVOS_FORMAT_SCORE; - else if (strncmp(format->string, "FRAMES", format->length) == 0) - return CHEEVOS_FORMAT_FRAMES; - else - return CHEEVOS_FORMAT_OTHER; -} - -static int cheevos_new_lboard(cheevos_readud_t *ud) -{ - cheevos_leaderboard_t *lboard = NULL; - cheevos_leaderboard_t *ldb = cheevos_locals.leaderboards; - - if (!ldb || !ud) - return -1; - - lboard = ldb + ud->lboard_count++; - - lboard->id = (unsigned)strtol(ud->id.string, NULL, 10); - lboard->format = cheevos_parse_format(&ud->format); - lboard->title = cheevos_dupstr(&ud->title); - lboard->description = cheevos_dupstr(&ud->desc); - - if (!lboard->title || !lboard->description) - goto error; - - if (cheevos_parse_mem(lboard, ud->memaddr.string)) - goto error; - - return 0; - -error: - if ((void*)lboard->title) - free((void*)lboard->title); - if ((void*)lboard->description) - free((void*)lboard->description); - return -1; -} - -static int cheevos_read__json_key( void *userdata, - const char *name, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - int common = ud->in_cheevos || ud->in_lboards; - uint32_t hash = cheevos_djb2(name, length); - ud->field = NULL; - - switch (hash) - { - case CHEEVOS_JSON_KEY_ACHIEVEMENTS: - ud->in_cheevos = 1; - break; - case CHEEVOS_JSON_KEY_LEADERBOARDS: - ud->in_lboards = 1; - break; - case CHEEVOS_JSON_KEY_CONSOLE_ID: - ud->is_console_id = 1; - break; - case CHEEVOS_JSON_KEY_ID: - if (common) - ud->field = &ud->id; - break; - case CHEEVOS_JSON_KEY_MEMADDR: - if (ud->in_cheevos) - ud->field = &ud->memaddr; - break; - case CHEEVOS_JSON_KEY_MEM: - if (ud->in_lboards) - ud->field = &ud->memaddr; - break; - case CHEEVOS_JSON_KEY_TITLE: - if (common) - ud->field = &ud->title; - break; - case CHEEVOS_JSON_KEY_DESCRIPTION: - if (common) - ud->field = &ud->desc; - break; - case CHEEVOS_JSON_KEY_POINTS: - if (ud->in_cheevos) - ud->field = &ud->points; - break; - case CHEEVOS_JSON_KEY_AUTHOR: - if (ud->in_cheevos) - ud->field = &ud->author; - break; - case CHEEVOS_JSON_KEY_MODIFIED: - if (ud->in_cheevos) - ud->field = &ud->modified; - break; - case CHEEVOS_JSON_KEY_CREATED: - if (ud->in_cheevos) - ud->field = &ud->created; - break; - case CHEEVOS_JSON_KEY_BADGENAME: - if (ud->in_cheevos) - ud->field = &ud->badge; - break; - case CHEEVOS_JSON_KEY_FLAGS: - if (ud->in_cheevos) - ud->field = &ud->flags; - break; - case CHEEVOS_JSON_KEY_FORMAT: - if (ud->in_lboards) - ud->field = &ud->format; - break; - default: - break; - } - } - - return 0; -} - -static int cheevos_read__json_string(void *userdata, - const char *string, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud && ud->field) - { - ud->field->string = string; - ud->field->length = length; - } - - return 0; -} - -static int cheevos_read__json_number(void *userdata, - const char *number, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - if (ud->field) - { - ud->field->string = number; - ud->field->length = length; - } - else if (ud->is_console_id) - { - cheevos_locals.console_id = (cheevos_console_t) - strtol(number, NULL, 10); - ud->is_console_id = 0; - } - } - - return 0; -} - -static int cheevos_read__json_end_object(void *userdata) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - if (ud->in_cheevos) - return cheevos_new_cheevo(ud); - if (ud->in_lboards) - return cheevos_new_lboard(ud); - } - - return 0; -} - -static int cheevos_read__json_end_array(void *userdata) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - ud->in_cheevos = 0; - ud->in_lboards = 0; - } - - return 0; -} - -static int cheevos_parse(const char *json) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - cheevos_read__json_end_object, - NULL, - cheevos_read__json_end_array, - cheevos_read__json_key, - NULL, - cheevos_read__json_string, - cheevos_read__json_number, - NULL, - NULL - }; - - cheevos_readud_t ud; - unsigned core_count, unofficial_count, lboard_count; - /* Count the number of achievements in the JSON file. */ - int res = cheevos_count_cheevos(json, &core_count, &unofficial_count, - &lboard_count); - - if (res != JSONSAX_OK) - return -1; - - /* Allocate the achievements. */ - - cheevos_locals.core.cheevos = (cheevo_t*) - calloc(core_count, sizeof(cheevo_t)); - cheevos_locals.core.count = core_count; - - cheevos_locals.unofficial.cheevos = (cheevo_t*) - calloc(unofficial_count, sizeof(cheevo_t)); - cheevos_locals.unofficial.count = unofficial_count; - - cheevos_locals.leaderboards = (cheevos_leaderboard_t*) - calloc(lboard_count, sizeof(cheevos_leaderboard_t)); - cheevos_locals.lboard_count = lboard_count; - - if ( !cheevos_locals.core.cheevos || - !cheevos_locals.unofficial.cheevos || - !cheevos_locals.leaderboards) - { - if ((void*)cheevos_locals.core.cheevos) - free((void*)cheevos_locals.core.cheevos); - if ((void*)cheevos_locals.unofficial.cheevos) - free((void*)cheevos_locals.unofficial.cheevos); - if ((void*)cheevos_locals.leaderboards) - free((void*)cheevos_locals.leaderboards); - cheevos_locals.core.count = cheevos_locals.unofficial.count = - cheevos_locals.lboard_count = 0; - - return -1; - } - - /* Load the achievements. */ - ud.in_cheevos = 0; - ud.in_lboards = 0; - ud.is_console_id = 0; - ud.field = NULL; - ud.core_count = 0; - ud.unofficial_count = 0; - ud.lboard_count = 0; - - if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK) - goto error; - - return 0; - -error: - cheevos_unload(); - - return -1; -} - -/***************************************************************************** -Test all the achievements (call once per frame). -*****************************************************************************/ - -static int cheevos_test_condition(cheevos_cond_t *cond) -{ - unsigned sval = 0; - unsigned tval = 0; - - if (!cond) - return 0; - - sval = cheevos_var_get_value(&cond->source) + - cheevos_locals.add_buffer; - tval = cheevos_var_get_value(&cond->target); - - switch (cond->op) - { - case CHEEVOS_COND_OP_EQUALS: - return (sval == tval); - case CHEEVOS_COND_OP_LESS_THAN: - return (sval < tval); - case CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL: - return (sval <= tval); - case CHEEVOS_COND_OP_GREATER_THAN: - return (sval > tval); - case CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL: - return (sval >= tval); - case CHEEVOS_COND_OP_NOT_EQUAL_TO: - return (sval != tval); - default: - break; - } - - return 1; -} - -static int cheevos_test_pause_cond_set(const cheevos_condset_t *condset, - int *dirty_conds, int *reset_conds, int process_pause) -{ - int cond_valid = 0; - int set_valid = 1; /* must start true so AND logic works */ - cheevos_cond_t *cond = NULL; - const cheevos_cond_t *end = condset->conds + condset->count; - - cheevos_locals.add_buffer = 0; - cheevos_locals.add_hits = 0; - - for (cond = condset->conds; cond < end; cond++) - { - if (cond->pause != process_pause) - continue; - - if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE) - { - cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source); - continue; - } - - if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE) - { - cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source); - continue; - } - - if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS) - { - if (cheevos_test_condition(cond)) - { - cond->curr_hits++; - *dirty_conds = 1; - } - - cheevos_locals.add_hits += cond->curr_hits; - continue; - } - - /* always evaluate the condition to ensure delta values get tracked correctly */ - cond_valid = cheevos_test_condition(cond); - - /* if the condition has a target hit count that has already been met, - * it's automatically true, even if not currently true. */ - if ( (cond->req_hits != 0) && - (cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits) - { - cond_valid = 1; - } - else if (cond_valid) - { - cond->curr_hits++; - *dirty_conds = 1; - - /* Process this logic, if this condition is true: */ - if (cond->req_hits == 0) - ; /* Not a hit-based requirement: ignore any additional logic! */ - else if ((cond->curr_hits + cheevos_locals.add_hits) < cond->req_hits) - cond_valid = 0; /* HitCount target has not yet been met, condition is not yet valid. */ - } - - cheevos_locals.add_buffer = 0; - cheevos_locals.add_hits = 0; - - if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) - { - /* as soon as we find a PauseIf that evaluates to true, - * stop processing the rest of the group. */ - if (cond_valid) - return 1; - - /* if we make it to the end of the function, make sure we are - * indicating nothing matched. if we do find a later PauseIf match, - * it'll automatically return true via the previous condition. */ - set_valid = 0; - - if (cond->req_hits == 0) - { - /* PauseIf didn't evaluate true, and doesn't have a HitCount, - * reset the HitCount to indicate the condition didn't match. */ - if (cond->curr_hits != 0) - { - cond->curr_hits = 0; - *dirty_conds = 1; - } - } - else - { - /* PauseIf has a HitCount that hasn't been met, ignore it for now. */ - } - } - else if (cond->type == CHEEVOS_COND_TYPE_RESET_IF) - { - if (cond_valid) - { - *reset_conds = 1; /* Resets all hits found so far */ - set_valid = 0; /* Cannot be valid if we've hit a reset condition. */ - } - } - else /* Sequential or non-sequential? */ - set_valid &= cond_valid; - } - - return set_valid; -} - -static int cheevos_test_cond_set(const cheevos_condset_t *condset, - int *dirty_conds, int *reset_conds) -{ - int in_pause = 0; - int has_pause = 0; - cheevos_cond_t *cond = NULL; - - if (!condset) - return 1; /* important: empty group must evaluate true */ - - /* the ints below are used for Pause conditions and their dependent AddSource/AddHits. */ - - /* this loop needs to go backwards to check AddSource/AddHits */ - cond = condset->conds + condset->count - 1; - for (; cond >= condset->conds; cond--) - { - if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) - { - has_pause = 1; - in_pause = 1; - cond->pause = 1; - } - else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE || - cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE || - cond->type == CHEEVOS_COND_TYPE_ADD_HITS) - { - cond->pause = in_pause; - } - else - { - in_pause = 0; - cond->pause = 0; - } - } - - if (has_pause) - { /* one or more Pause conditions exists, if any of them are true, - * stop processing this group. */ - if (cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 1)) - return 0; - } - - /* process the non-Pause conditions to see if the group is true */ - return cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 0); -} - -static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas) -{ - int dirty = 0; - const cheevos_cond_t *end = NULL; - - if (!condset) - return 0; - - end = condset->conds + condset->count; - - if (deltas) - { - cheevos_cond_t *cond = NULL; - for (cond = condset->conds; cond < end; cond++) - { - dirty |= cond->curr_hits != 0; - - cond->curr_hits = 0; - - cond->source.previous = cond->source.value; - cond->target.previous = cond->target.value; - } - } - else - { - cheevos_cond_t *cond = NULL; - for (cond = condset->conds; cond < end; cond++) - { - dirty |= cond->curr_hits != 0; - cond->curr_hits = 0; - } - } - - return dirty; -} - -static int cheevos_test_cheevo(cheevo_t *cheevo) -{ - int dirty_conds = 0; - int reset_conds = 0; - int ret_val = 0; - int ret_val_sub_cond = 0; - cheevos_condset_t *condset = NULL; - cheevos_condset_t *end = NULL; - - if (!cheevo) - return 0; - - ret_val_sub_cond = cheevo->condition.count == 1; - condset = cheevo->condition.condsets; - - if (!condset) - return 0; - - end = condset + cheevo->condition.count; - - if (condset < end) - { - ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds); - condset++; - } - - while (condset < end) - { - ret_val_sub_cond |= cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - if (dirty_conds) - cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; - - if (reset_conds) - { - int dirty = 0; - - for (condset = cheevo->condition.condsets; condset < end; condset++) - dirty |= cheevos_reset_cond_set(condset, 0); - - if (dirty) - cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; - } - - return (ret_val && ret_val_sub_cond); -} - -static void cheevos_url_encode(const char *str, char *encoded, size_t len) -{ - if (!str) - return; - - while (*str) - { - if ( isalnum((unsigned char)*str) || *str == '-' - || *str == '_' || *str == '.' - || *str == '~') - { - if (len >= 2) - { - *encoded++ = *str++; - len--; - } - else - break; - } - else - { - if (len >= 4) - { - snprintf(encoded, len, "%%%02x", (uint8_t)*str); - encoded += 3; - str++; - len -= 3; - } - else - break; - } - } - - *encoded = 0; -} - -static void cheevos_make_unlock_url(const cheevo_t *cheevo, - char* url, size_t url_size) -{ - settings_t *settings = config_get_ptr(); - - if (!settings) - return; - - snprintf( - url, url_size, - "http://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d", - settings->arrays.cheevos_username, - cheevos_locals.token, - cheevo->id, - settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused ? 1 : 0 - ); - - url[url_size - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to award the cheevo: %s\n", url); -#endif -} - -static void cheevos_unlocked(void *task_data, void *user_data, - const char *error) -{ - cheevo_t *cheevo = (cheevo_t *)user_data; - - if (!error) - { - CHEEVOS_LOG("[CHEEVOS]: awarded achievement %u.\n", cheevo->id); - } - else - { - char url[256]; - url[0] = '\0'; - - CHEEVOS_ERR("[CHEEVOS]: error awarding achievement %u, retrying...\n", cheevo->id); - - cheevos_make_unlock_url(cheevo, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, cheevos_unlocked, cheevo); - } -} - -static void cheevos_test_cheevo_set(const cheevoset_t *set) -{ - settings_t *settings = config_get_ptr(); - int mode = CHEEVOS_ACTIVE_SOFTCORE; - cheevo_t *cheevo = NULL; - const cheevo_t *end = NULL; - - if (!set) - return; - - end = set->cheevos + set->count; - - if (settings && settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - mode = CHEEVOS_ACTIVE_HARDCORE; - - for (cheevo = set->cheevos; cheevo < end; cheevo++) - { - if (cheevo->active & mode) - { - int valid = cheevos_test_cheevo(cheevo); - - if (cheevo->last) - { - cheevos_condset_t* condset = cheevo->condition.condsets; - const cheevos_condset_t* end = cheevo->condition.condsets - + cheevo->condition.count; - - for (; condset < end; condset++) - cheevos_reset_cond_set(condset, 0); - } - else if (valid) - { - char msg[256]; - char url[256]; - msg[0] = url[0] = '\0'; - - cheevo->active &= ~mode; - - if (mode == CHEEVOS_ACTIVE_HARDCORE) - cheevo->active &= ~CHEEVOS_ACTIVE_SOFTCORE; - - CHEEVOS_LOG("[CHEEVOS]: awarding cheevo %u: %s (%s).\n", - cheevo->id, cheevo->title, cheevo->description); - - snprintf(msg, sizeof(msg), "Achievement Unlocked: %s", - cheevo->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false); - - cheevos_make_unlock_url(cheevo, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, - cheevos_unlocked, cheevo); - - if (settings && settings->bools.cheevos_auto_screenshot) - { - char shotname[256]; - - snprintf(shotname, sizeof(shotname), "%s/%s-cheevo-%u", - settings->paths.directory_screenshot, - path_basename(path_get(RARCH_PATH_BASENAME)), - cheevo->id); - shotname[sizeof(shotname) - 1] = '\0'; - - if (take_screenshot(shotname, true, - video_driver_cached_frame_has_valid_framebuffer(), false, true)) - CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); - else - CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); - } - } - - cheevo->last = valid; - } - } -} - -static int cheevos_test_lboard_condition(const cheevos_condition_t* condition) -{ - int dirty_conds = 0; - int reset_conds = 0; - int ret_val = 0; - int ret_val_sub_cond = 0; - cheevos_condset_t *condset = NULL; - const cheevos_condset_t *end = NULL; - - if (!condition) - return 0; - - ret_val_sub_cond = condition->count == 1; - condset = condition->condsets; - end = condset + condition->count; - - if (condset < end) - { - ret_val = cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - while (condset < end) - { - ret_val_sub_cond |= cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - if (reset_conds) - { - for (condset = condition->condsets; condset < end; condset++) - cheevos_reset_cond_set(condset, 0); - } - - return (ret_val && ret_val_sub_cond); -} - -static int cheevos_expr_value(cheevos_expr_t* expr) -{ - unsigned i; - int values[16]; - /* Separate possible values with '$' operator, submit the largest */ - unsigned current_value = 0; - cheevos_term_t* term = NULL; - - if (!expr) - return 0; - - term = expr->terms; - - if (!term) - return 0; - - if (expr->compare_count >= ARRAY_SIZE(values)) - { - CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", expr->compare_count); - return 0; - } - - memset(values, 0, sizeof values); - - for (i = expr->count; i != 0; i--, term++) - { - if (current_value >= ARRAY_SIZE(values)) - { - CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", current_value); - return 0; - } - - values[current_value] += - cheevos_var_get_value(&term->var) * term->multiplier; - - if (term->compare_next) - current_value++; - } - - if (expr->compare_count > 1) - { - unsigned j; - int maximum = values[0]; - - for (j = 1; j < expr->compare_count; j++) - maximum = values[j] > maximum ? values[j] : maximum; - - return maximum; - } - else - return values[0]; -} - -static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, - char* url, size_t url_size) -{ - MD5_CTX ctx; - uint8_t hash[16]; - char signature[64]; - settings_t *settings = config_get_ptr(); - - hash[0] = '\0'; - - snprintf(signature, sizeof(signature), "%u%s%u", lboard->id, - settings->arrays.cheevos_username, - lboard->id); - - MD5_Init(&ctx); - MD5_Update(&ctx, (void*)signature, strlen(signature)); - MD5_Final(hash, &ctx); - - snprintf( - url, url_size, - "http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d" - "&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - settings->arrays.cheevos_username, - cheevos_locals.token, - lboard->id, - lboard->last_value, - hash[ 0], hash[ 1], hash[ 2], hash[ 3], - hash[ 4], hash[ 5], hash[ 6], hash[ 7], - hash[ 8], hash[ 9], hash[10], hash[11], - hash[12], hash[13], hash[14], hash[15] - ); - - url[url_size - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to submit the leaderboard: %s\n", url); -#endif -} - -static void cheevos_lboard_submit(void *task_data, void *user_data, - const char *error) -{ - cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; - - if (!lboard) - return; - - if (!error) - { - CHEEVOS_ERR("[CHEEVOS]: error submitting leaderboard %u\n", lboard->id); - return; - } - - CHEEVOS_LOG("[CHEEVOS]: submitted leaderboard %u.\n", lboard->id); -} - -static void cheevos_test_leaderboards(void) -{ - unsigned i; - cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards; - - if (!lboard) - return; - - for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++) - { - if (lboard->active) - { - int value = cheevos_expr_value(&lboard->value); - - if (value != lboard->last_value) - { - CHEEVOS_LOG("[CHEEVOS]: value lboard %s %u\n", - lboard->title, value); - lboard->last_value = value; - } - - if (cheevos_test_lboard_condition(&lboard->submit)) - { - lboard->active = 0; - - /* failsafe for improper LBs */ - if (value == 0) - { - CHEEVOS_LOG("[CHEEVOS]: error: lboard %s tried to submit 0\n", - lboard->title); - runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); - } - else - { - char url[256]; - char msg[256]; - char formatted_value[16]; - - cheevos_make_lboard_url(lboard, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, - cheevos_lboard_submit, lboard); - CHEEVOS_LOG("[CHEEVOS]: submit lboard %s\n", lboard->title); - - cheevos_format_value(value, lboard->format, - formatted_value, sizeof(formatted_value)); - snprintf(msg, sizeof(msg), "Submitted %s for %s", - formatted_value, lboard->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - } - } - - if (cheevos_test_lboard_condition(&lboard->cancel)) - { - CHEEVOS_LOG("[CHEEVOS]: cancel lboard %s\n", lboard->title); - lboard->active = 0; - runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); - } - } - else - { - if (cheevos_test_lboard_condition(&lboard->start)) - { - char msg[256]; - - CHEEVOS_LOG("[CHEEVOS]: start lboard %s\n", lboard->title); - lboard->active = 1; - lboard->last_value = -1; - - snprintf(msg, sizeof(msg), - "Leaderboard Active: %s", lboard->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(lboard->description, 0, 3*60, false); - } - } - } -} - -/***************************************************************************** -Free the loaded achievements. -*****************************************************************************/ - -static void cheevos_free_condset(const cheevos_condset_t *set) -{ - if (set && set->conds) - free((void*)set->conds); -} - -static void cheevos_free_cheevo(const cheevo_t *cheevo) -{ - if (!cheevo) - return; - - if (cheevo->title) - free((void*)cheevo->title); - if (cheevo->description) - free((void*)cheevo->description); - if (cheevo->author) - free((void*)cheevo->author); - if (cheevo->badge) - free((void*)cheevo->badge); - cheevos_free_condset(cheevo->condition.condsets); -} - -static void cheevos_free_cheevo_set(const cheevoset_t *set) -{ - const cheevo_t *cheevo = NULL; - const cheevo_t *end = NULL; - - if (!set) - return; - - cheevo = set->cheevos; - end = cheevo + set->count; - - while (cheevo < end) - cheevos_free_cheevo(cheevo++); - - if (set->cheevos) - free((void*)set->cheevos); -} - -#ifndef CHEEVOS_DONT_DEACTIVATE -static int cheevos_deactivate__json_index(void *userdata, unsigned int index) -{ - cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; - - if (ud) - ud->is_element = 1; - - return 0; -} - -static int cheevos_deactivate__json_number(void *userdata, - const char *number, size_t length) -{ - long id; - int found; - cheevo_t* cheevo = NULL; - const cheevo_t* end = NULL; - cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; - - if (ud && ud->is_element) - { - ud->is_element = 0; - id = strtol(number, NULL, 10); - found = 0; - cheevo = cheevos_locals.core.cheevos; - end = cheevo + cheevos_locals.core.count; - - for (; cheevo < end; cheevo++) - { - if (cheevo->id == (unsigned)id) - { - cheevo->active &= ~ud->mode; - found = 1; - break; - } - } - - if (!found) - { - cheevo = cheevos_locals.unofficial.cheevos; - end = cheevo + cheevos_locals.unofficial.count; - - for (; cheevo < end; cheevo++) - { - if (cheevo->id == (unsigned)id) - { - cheevo->active &= ~ud->mode; - found = 1; - break; - } - } - } - - if (found) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked cheevo %u (%s).\n", - cheevo->id, cheevo->title); - else - CHEEVOS_ERR("[CHEEVOS]: unknown cheevo to deactivate: %u.\n", id); - } - - return 0; -} - -static int cheevos_deactivate_unlocks(const char* json, unsigned mode) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_deactivate__json_index, - NULL, - cheevos_deactivate__json_number, - NULL, - NULL - }; - - cheevos_deactivate_t ud; - - ud.is_element = 0; - ud.mode = mode; - return jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK; -} -#endif - -void cheevos_reset_game(void) -{ - cheevo_t *end = NULL; - cheevo_t *cheevo = cheevos_locals.core.cheevos; - - if (!cheevo) - return; - - end = cheevo + cheevos_locals.core.count; - - for (; cheevo < end; cheevo++) - cheevo->last = 1; - - cheevo = cheevos_locals.unofficial.cheevos; - end = cheevo + cheevos_locals.unofficial.count; - - for (; cheevo < end; cheevo++) - cheevo->last = 1; -} - -void cheevos_populate_menu(void *data) -{ -#ifdef HAVE_MENU - unsigned i = 0; - unsigned items_found = 0; - settings_t *settings = config_get_ptr(); - menu_displaylist_info_t *info = (menu_displaylist_info_t*)data; - cheevo_t *end = NULL; - cheevo_t *cheevo = cheevos_locals.core.cheevos; - end = cheevo + cheevos_locals.core.count; - - if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable - && cheevos_loaded) - { - if (!cheevos_hardcore_paused) - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE), - msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE), - MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE, - MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0); - else - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME), - msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME), - MENU_ENUM_LABEL_ACHIEVEMENT_RESUME, - MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0); - } - - if (cheevo) - { - for (i = 0; cheevo < end; i++, cheevo++) - { - if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); - } - else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - else - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - items_found++; - } - } - - cheevo = cheevos_locals.unofficial.cheevos; - - if (cheevo && settings->bools.cheevos_test_unofficial) - { - end = cheevo + cheevos_locals.unofficial.count; - - for (i = items_found; cheevo < end; i++, cheevo++) - { - if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); - } - else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - else - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - items_found++; - } - } - - if (items_found == 0) - { - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY), - msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY), - MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY, - FILE_TYPE_NONE, 0, 0); - } -#endif -} - -bool cheevos_get_description(cheevos_ctx_desc_t *desc) -{ - if (!desc) - return false; - - if (cheevos_loaded) - { - cheevo_t *cheevos = cheevos_locals.core.cheevos; - - if (!cheevos) - return false; - - if (desc->idx >= cheevos_locals.core.count) - { - cheevos = cheevos_locals.unofficial.cheevos; - desc->idx -= cheevos_locals.core.count; - } - - if (!string_is_empty(cheevos[desc->idx].description)) - strlcpy(desc->s, cheevos[desc->idx].description, desc->len); - } - else - *desc->s = 0; - - return true; -} - -bool cheevos_apply_cheats(bool *data_bool) -{ - cheats_are_enabled = *data_bool; - cheats_were_enabled |= cheats_are_enabled; - - return true; -} - -bool cheevos_unload(void) -{ - bool running; - CHEEVOS_LOCK(cheevos_locals.task_lock); - running = cheevos_locals.task != NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - if (running) - { - CHEEVOS_LOG("[CHEEVOS]: Asked the load thread to terminate\n"); - task_queue_cancel_task(cheevos_locals.task); - -#ifdef HAVE_THREADS - do - { - CHEEVOS_LOCK(cheevos_locals.task_lock); - running = cheevos_locals.task != NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - } - while (running); -#endif - } - - if (cheevos_loaded) - { - cheevos_free_cheevo_set(&cheevos_locals.core); - cheevos_free_cheevo_set(&cheevos_locals.unofficial); - } - - cheevos_locals.core.cheevos = NULL; - cheevos_locals.unofficial.cheevos = NULL; - cheevos_locals.core.count = 0; - cheevos_locals.unofficial.count = 0; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - - return true; -} - -bool cheevos_toggle_hardcore_mode(void) -{ - settings_t *settings = config_get_ptr(); - - if (!settings) - return false; - - /* reset and deinit rewind to avoid cheat the score */ - if (settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - { - const char *msg = msg_hash_to_str( - MSG_CHEEVOS_HARDCORE_MODE_ENABLE); - - /* send reset core cmd to avoid any user - * savestate previusly loaded. */ - command_event(CMD_EVENT_RESET, NULL); - - if (settings->bools.rewind_enable) - command_event(CMD_EVENT_REWIND_DEINIT, NULL); - - CHEEVOS_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 0, 3 * 60, true); - } - else - { - if (settings->bools.rewind_enable) - command_event(CMD_EVENT_REWIND_INIT, NULL); - } - - return true; -} - -static void cheevos_patch_addresses(cheevoset_t* set) -{ - unsigned i; - cheevo_t* cheevo = NULL; - - if (!set) - return; - - cheevo = set->cheevos; - - if (!cheevo) - return; - - for (i = set->count; i != 0; i--, cheevo++) - { - unsigned j; - cheevos_condset_t* condset = cheevo->condition.condsets; - - for (j = cheevo->condition.count; j != 0; j--, condset++) - { - unsigned k; - cheevos_cond_t* cond = condset->conds; - - for (k = condset->count; k != 0; k--, cond++) - { - switch (cond->source.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->source, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - cond->source.bank_id + 1, cond->source.value); -#endif - break; - - default: - break; - } - - switch (cond->target.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->target, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", - cond->target.bank_id + 1, cond->target.value); -#endif - break; - - default: - break; - } - } - } - } -} - -static void cheevos_patch_lb_conditions(cheevos_condition_t* condition) -{ - unsigned i; - cheevos_condset_t* condset = NULL; - - if (!condition) - return; - - condset = condition->condsets; - - for (i = condition->count; i != 0; i--, condset++) - { - unsigned j; - cheevos_cond_t* cond = condset->conds; - - for (j = condset->count; j != 0; j--, cond++) - { - switch (cond->source.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->source, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - cond->source.bank_id + 1, cond->source.value); -#endif - break; - default: - break; - } - switch (cond->target.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->target, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", - cond->target.bank_id + 1, cond->target.value); -#endif - break; - default: - break; - } - } - } -} - -static void cheevos_patch_lb_expressions(cheevos_expr_t* expression) -{ - unsigned i; - cheevos_term_t* term = NULL; - - if (!expression) - return; - - term = expression->terms; - - for (i = expression->count; i != 0; i--, term++) - { - switch (term->var.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&term->var, cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - term->var.bank_id + 1, term->var.value); -#endif - break; - default: - break; - } - } -} - -static void cheevos_patch_lbs(cheevos_leaderboard_t *leaderboard) -{ - unsigned i; - - for (i = 0; i < cheevos_locals.lboard_count; i++) - { - cheevos_condition_t *start = &leaderboard[i].start; - cheevos_condition_t *cancel = &leaderboard[i].cancel; - cheevos_condition_t *submit = &leaderboard[i].submit; - cheevos_expr_t *value = &leaderboard[i].value; - - cheevos_patch_lb_conditions(start); - cheevos_patch_lb_conditions(cancel); - cheevos_patch_lb_conditions(submit); - cheevos_patch_lb_expressions(value); - } -} - -void cheevos_test(void) -{ - settings_t *settings = config_get_ptr(); - - if (!cheevos_locals.addrs_patched) - { - cheevos_patch_addresses(&cheevos_locals.core); - cheevos_patch_addresses(&cheevos_locals.unofficial); - cheevos_patch_lbs(cheevos_locals.leaderboards); - - cheevos_locals.addrs_patched = true; - } - - cheevos_test_cheevo_set(&cheevos_locals.core); - - if (settings) - { - if (settings->bools.cheevos_test_unofficial) - cheevos_test_cheevo_set(&cheevos_locals.unofficial); - - if (settings->bools.cheevos_hardcore_mode_enable && - settings->bools.cheevos_leaderboards_enable && - !cheevos_hardcore_paused) - cheevos_test_leaderboards(); - } -} - -bool cheevos_set_cheats(void) -{ - cheats_were_enabled = cheats_are_enabled; - return true; -} - -void cheevos_set_support_cheevos(bool state) -{ - cheevos_locals.core_supports = state; -} - -bool cheevos_get_support_cheevos(void) -{ - return cheevos_locals.core_supports; -} - -cheevos_console_t cheevos_get_console(void) -{ - return cheevos_locals.console_id; -} - -#include "coro.h" - -/* Uncomment the following two lines to debug cheevos_iterate, this will - * disable the coroutine yielding. - * - * The code is very easy to understand. It's meant to be like BASIC: - * CORO_GOTO will jump execution to another label, CORO_GOSUB will - * call another label, and CORO_RET will return from a CORO_GOSUB. - * - * This coroutine code is inspired in a very old pure C implementation - * that runs everywhere: - * - * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - */ -/*#undef CORO_YIELD -#define CORO_YIELD()*/ - -typedef struct -{ - /* variables used in the co-routine */ - char badge_name[16]; - char url[256]; - char badge_basepath[PATH_MAX_LENGTH]; - char badge_fullpath[PATH_MAX_LENGTH]; - unsigned char hash[16]; - bool round; - unsigned gameid; - unsigned i; - unsigned j; - unsigned k; - size_t bytes; - size_t count; - size_t offset; - size_t len; - size_t size; - MD5_CTX md5; - cheevos_nes_header_t header; - retro_time_t t0; - struct retro_system_info sysinfo; - void *data; - char *json; - const char *path; - const char *ext; - intfstream_t *stream; - cheevo_t *cheevo; - settings_t *settings; - struct http_connection_t *conn; - struct http_t *http; - const cheevo_t *cheevo_end; - - /* co-routine required fields */ - CORO_FIELDS -} coro_t; - -enum -{ - /* Negative values because CORO_SUB generates positive values */ - SNES_MD5 = -1, - GENESIS_MD5 = -2, - LYNX_MD5 = -3, - NES_MD5 = -4, - GENERIC_MD5 = -5, - FILENAME_MD5 = -6, - EVAL_MD5 = -7, - FILL_MD5 = -8, - GET_GAMEID = -9, - GET_CHEEVOS = -10, - GET_BADGES = -11, - LOGIN = -12, - HTTP_GET = -13, - DEACTIVATE = -14, - PLAYING = -15, - DELAY = -16 -}; - -static int cheevos_iterate(coro_t *coro) -{ - ssize_t num_read = 0; - size_t to_read = 4096; - uint8_t *buffer = NULL; - const char *end = NULL; - - static const uint32_t genesis_exts[] = - { - 0x0b888feeU, /* mdx */ - 0x005978b6U, /* md */ - 0x0b88aa89U, /* smd */ - 0x0b88767fU, /* gen */ - 0x0b8861beU, /* bin */ - 0x0b886782U, /* cue */ - 0x0b8880d0U, /* iso */ - 0x0b88aa98U, /* sms */ - 0x005977f3U, /* gg */ - 0x0059797fU, /* sg */ - 0 - }; - - static const uint32_t snes_exts[] = - { - 0x0b88aa88U, /* smc */ - 0x0b8872bbU, /* fig */ - 0x0b88a9a1U, /* sfc */ - 0x0b887623U, /* gd3 */ - 0x0b887627U, /* gd7 */ - 0x0b886bf3U, /* dx2 */ - 0x0b886312U, /* bsx */ - 0x0b88abd2U, /* swc */ - 0 - }; - - static const uint32_t lynx_exts[] = - { - 0x0b888cf7U, /* lnx */ - 0 - }; - - static cheevos_finder_t finders[] = - { - {SNES_MD5, "SNES (8Mb padding)", snes_exts}, - {GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts}, - {LYNX_MD5, "Atari Lynx (only first 512 bytes)", lynx_exts}, - {NES_MD5, "NES (discards VROM)", NULL}, - {GENERIC_MD5, "Generic (plain content)", NULL}, - {FILENAME_MD5, "Generic (filename)", NULL} - }; - - CORO_ENTER(); - - - - cheevos_locals.addrs_patched = false; - - coro->settings = config_get_ptr(); - - cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM; - core_get_memory(&cheevos_locals.meminfo[0]); - - cheevos_locals.meminfo[1].id = RETRO_MEMORY_SAVE_RAM; - core_get_memory(&cheevos_locals.meminfo[1]); - - cheevos_locals.meminfo[2].id = RETRO_MEMORY_VIDEO_RAM; - core_get_memory(&cheevos_locals.meminfo[2]); - - cheevos_locals.meminfo[3].id = RETRO_MEMORY_RTC; - core_get_memory(&cheevos_locals.meminfo[3]); - - CHEEVOS_LOG("[CHEEVOS]: system RAM: %p %u\n", - cheevos_locals.meminfo[0].data, - cheevos_locals.meminfo[0].size); - CHEEVOS_LOG("[CHEEVOS]: save RAM: %p %u\n", - cheevos_locals.meminfo[1].data, - cheevos_locals.meminfo[1].size); - CHEEVOS_LOG("[CHEEVOS]: video RAM: %p %u\n", - cheevos_locals.meminfo[2].data, - cheevos_locals.meminfo[2].size); - CHEEVOS_LOG("[CHEEVOS]: RTC: %p %u\n", - cheevos_locals.meminfo[3].data, - cheevos_locals.meminfo[3].size); - - /* Bail out if cheevos are disabled. - * But set the above anyways, - * command_read_ram needs it. */ - if (!coro->settings->bools.cheevos_enable) - CORO_STOP(); - - /* Load the content into memory, or copy it - * over to our own buffer */ - if (!coro->data) - { - coro->stream = intfstream_open_file( - coro->path, - RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE); - - if (!coro->stream) - CORO_STOP(); - - CORO_YIELD(); - coro->len = 0; - coro->count = intfstream_get_size(coro->stream); - - /* size limit */ - if (coro->count > size_in_megabytes(64)) - coro->count = size_in_megabytes(64); - - coro->data = malloc(coro->count); - - if (!coro->data) - { - intfstream_close(coro->stream); - free(coro->stream); - CORO_STOP(); - } - - for (;;) - { - buffer = (uint8_t*)coro->data + coro->len; - to_read = 4096; - - if (to_read > coro->count) - to_read = coro->count; - - num_read = intfstream_read(coro->stream, - (void*)buffer, to_read); - - if (num_read <= 0) - break; - - coro->len += num_read; - coro->count -= num_read; - - if (coro->count == 0) - break; - - CORO_YIELD(); - } - - intfstream_close(coro->stream); - free(coro->stream); - } - - /* Use the supported extensions as a hint - * to what method we should use. */ - core_get_system_info(&coro->sysinfo); - - for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) - { - if (finders[coro->i].ext_hashes) - { - coro->ext = coro->sysinfo.valid_extensions; - - while (coro->ext) - { - unsigned hash; - end = strchr(coro->ext, '|'); - - if (end) - { - hash = cheevos_djb2( - coro->ext, end - coro->ext); - coro->ext = end + 1; - } - else - { - hash = cheevos_djb2( - coro->ext, strlen(coro->ext)); - coro->ext = NULL; - } - - for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++) - { - if (finders[coro->i].ext_hashes[coro->j] == hash) - { - CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", - finders[coro->i].name); - - /* - * Inputs: CHEEVOS_VAR_INFO - * Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0 - */ - CORO_GOSUB(finders[coro->i].label); - - if (coro->gameid != 0) - goto found; - - coro->ext = NULL; /* force next finder */ - break; - } - } - } - } - } - - for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) - { - if (finders[coro->i].ext_hashes) - continue; - - CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", - finders[coro->i].name); - - /* - * Inputs: CHEEVOS_VAR_INFO - * Outputs: CHEEVOS_VAR_GAMEID - */ - CORO_GOSUB(finders[coro->i].label); - - if (coro->gameid != 0) - goto found; - } - - CHEEVOS_LOG("[CHEEVOS]: this game doesn't feature achievements.\n"); - CORO_STOP(); - -found: - -#ifdef CHEEVOS_JSON_OVERRIDE - { - size_t size = 0; - FILE *file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); - - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, 0, SEEK_SET); - - coro->json = (char*)malloc(size + 1); - fread((void*)coro->json, 1, size, file); - - fclose(file); - coro->json[size] = 0; - } -#else - CORO_GOSUB(GET_CHEEVOS); - - if (!coro->json) - { - runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: error loading achievements.\n"); - CORO_STOP(); - } -#endif - -#ifdef CHEEVOS_SAVE_JSON - { - FILE *file = fopen(CHEEVOS_SAVE_JSON, "w"); - fwrite((void*)coro->json, 1, strlen(coro->json), file); - fclose(file); - } -#endif - if (cheevos_parse(coro->json)) - { - if ((void*)coro->json) - free((void*)coro->json); - CORO_STOP(); - } - - if ((void*)coro->json) - free((void*)coro->json); - - if ( cheevos_locals.core.count == 0 - && cheevos_locals.unofficial.count == 0 - && cheevos_locals.lboard_count == 0) - { - runloop_msg_queue_push( - "This game has no achievements.", - 0, 5 * 60, false); - - cheevos_free_cheevo_set(&cheevos_locals.core); - cheevos_free_cheevo_set(&cheevos_locals.unofficial); - - cheevos_locals.core.cheevos = NULL; - cheevos_locals.unofficial.cheevos = NULL; - cheevos_locals.core.count = 0; - cheevos_locals.unofficial.count = 0; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - CORO_STOP(); - } - - cheevos_loaded = true; - - /* - * Inputs: CHEEVOS_VAR_GAMEID - * Outputs: - */ - CORO_GOSUB(DEACTIVATE); - - /* - * Inputs: CHEEVOS_VAR_GAMEID - * Outputs: - */ - CORO_GOSUB(PLAYING); - - if (coro->settings->bools.cheevos_verbose_enable && cheevos_locals.core.count > 0) - { - char msg[256]; - int mode = CHEEVOS_ACTIVE_SOFTCORE; - const cheevo_t* cheevo = cheevos_locals.core.cheevos; - const cheevo_t* end = cheevo + cheevos_locals.core.count; - int number_of_unlocked = cheevos_locals.core.count; - - if (coro->settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - mode = CHEEVOS_ACTIVE_HARDCORE; - - for (; cheevo < end; cheevo++) - if (cheevo->active & mode) - number_of_unlocked--; - - snprintf(msg, sizeof(msg), - "You have %d of %d achievements unlocked.", - number_of_unlocked, cheevos_locals.core.count); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 6 * 60, false); - } - - CORO_GOSUB(GET_BADGES); - CORO_STOP(); - - /************************************************************************** - * Info Tries to identify a SNES game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(SNES_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - - CORO_GOSUB(EVAL_MD5); - - if (coro->count == 0) - { - MD5_Final(coro->hash, &coro->md5); - coro->gameid = 0; - CORO_RET(); - } - - if (coro->count < size_in_megabytes(8)) - { - /* - * Inputs: CHEEVOS_VAR_MD5, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs: CHEEVOS_VAR_MD5 - */ - coro->offset = 0; - coro->count = size_in_megabytes(8) - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a Genesis game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(GENESIS_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - CORO_GOSUB(EVAL_MD5); - - if (coro->count == 0) - { - MD5_Final(coro->hash, &coro->md5); - coro->gameid = 0; - CORO_RET(); - } - - if (coro->count < size_in_megabytes(6)) - { - coro->offset = 0; - coro->count = size_in_megabytes(6) - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify an Atari Lynx game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(LYNX_MD5) - - if (coro->len < 0x0240) - { - coro->gameid = 0; - CORO_RET(); - } - - MD5_Init(&coro->md5); - - coro->offset = 0x0040; - coro->count = 0x0200; - CORO_GOSUB(EVAL_MD5); - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a NES game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(NES_MD5) - - /* Note about the references to the FCEU emulator below. There is no - * core-specific code in this function, it's rather Retro Achievements - * specific code that must be followed to the letter so we compute - * the correct ROM hash. Retro Achievements does indeed use some - * FCEU related method to compute the hash, since its NES emulator - * is based on it. */ - - if (coro->len < sizeof(coro->header)) - { - coro->gameid = 0; - CORO_RET(); - } - - memcpy((void*)&coro->header, coro->data, - sizeof(coro->header)); - - if ( coro->header.id[0] != 'N' - || coro->header.id[1] != 'E' - || coro->header.id[2] != 'S' - || coro->header.id[3] != 0x1a) - { - coro->gameid = 0; - CORO_RET(); - } - - { - size_t romsize = 256; - /* from FCEU core - compute size using the cart mapper */ - int mapper = (coro->header.rom_type >> 4) | (coro->header.rom_type2 & 0xF0); - - if (coro->header.rom_size) - romsize = next_pow2(coro->header.rom_size); - - /* for games not to the power of 2, so we just read enough - * PRG rom from it, but we have to keep ROM_size to the power of 2 - * since PRGCartMapping wants ROM_size to be to the power of 2 - * so instead if not to power of 2, we just use head.ROM_size when - * we use FCEU_read. */ - coro->round = mapper != 53 && mapper != 198 && mapper != 228; - coro->bytes = coro->round ? romsize : coro->header.rom_size; - } - - /* from FCEU core - check if Trainer included in ROM data */ - MD5_Init(&coro->md5); - coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4 - ? sizeof(coro->header) : 0); - coro->count = 0x4000 * coro->bytes; - CORO_GOSUB(EVAL_MD5); - - if (coro->count < 0x4000 * coro->bytes) - { - coro->offset = 0xff; - coro->count = 0x4000 * coro->bytes - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a "generic" game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(GENERIC_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - CORO_GOSUB(EVAL_MD5); - - MD5_Final(coro->hash, &coro->md5); - - if (coro->count == 0) - CORO_RET(); - - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a game based on its filename (with no extension) - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(FILENAME_MD5) - if (!string_is_empty(coro->path)) - { - char base_noext[PATH_MAX_LENGTH]; - fill_pathname_base_noext(base_noext, coro->path, sizeof(base_noext)); - - MD5_Init(&coro->md5); - MD5_Update(&coro->md5, (void*)base_noext, strlen(base_noext)); - MD5_Final(coro->hash, &coro->md5); - - CORO_GOTO(GET_GAMEID); - } - CORO_RET(); - - /************************************************************************** - * Info Evaluates the CHEEVOS_VAR_MD5 hash - * Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT - *************************************************************************/ - CORO_SUB(EVAL_MD5) - - if (coro->count == 0) - coro->count = coro->len; - - if (coro->len - coro->offset < coro->count) - coro->count = coro->len - coro->offset; - - /* size limit */ - if (coro->count > size_in_megabytes(64)) - coro->count = size_in_megabytes(64); - - MD5_Update(&coro->md5, - (void*)((uint8_t*)coro->data + coro->offset), - coro->count); - CORO_RET(); - - /************************************************************************** - * Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value - * Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs CHEEVOS_VAR_MD5 - *************************************************************************/ - CORO_SUB(FILL_MD5) - - { - char buffer[4096]; - - while (coro->count > 0) - { - size_t len = sizeof(buffer); - - if (len > coro->count) - len = coro->count; - - memset((void*)buffer, coro->offset, len); - MD5_Update(&coro->md5, (void*)buffer, len); - coro->count -= len; - } - } - - CORO_RET(); - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs coro->hash - * Outputs CHEEVOS_VAR_GAMEID - *************************************************************************/ - CORO_SUB(GET_GAMEID) - - { - char gameid[16]; - - CHEEVOS_LOG( - "[CHEEVOS]: getting game id for hash %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", - coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], - coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], - coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], - coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] - ); - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=gameid&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], - coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], - coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], - coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the game's id: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (!coro->json) - CORO_RET(); - - if (cheevos_get_value(coro->json, - CHEEVOS_JSON_KEY_GAMEID, gameid, sizeof(gameid))) - { - if ((void*)coro->json) - free((void*)coro->json); - CHEEVOS_ERR("[CHEEVOS]: error getting game_id.\n"); - CORO_RET(); - } - - if ((void*)coro->json) - free((void*)coro->json); - CHEEVOS_LOG("[CHEEVOS]: got game id %s.\n", gameid); - coro->gameid = (unsigned)strtol(gameid, NULL, 10); - CORO_RET(); - } - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(GET_CHEEVOS) - - CORO_GOSUB(LOGIN); - - snprintf(coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=patch&g=%u&u=%s&t=%s", - coro->gameid, - coro->settings->arrays.cheevos_username, - cheevos_locals.token); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of cheevos: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (!coro->json) - { - CHEEVOS_ERR("[CHEEVOS]: error getting achievements for game id %u.\n", coro->gameid); - CORO_STOP(); - } - - CHEEVOS_LOG("[CHEEVOS]: got achievements for game id %u.\n", coro->gameid); - CORO_RET(); - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(GET_BADGES) - - badges_ctx = new_badges_ctx; - - { - settings_t *settings = config_get_ptr(); - if (!( - string_is_equal(settings->arrays.menu_driver, "xmb") || - !string_is_equal(settings->arrays.menu_driver, "ozone") - ) || - !settings->bools.cheevos_badges_enable) - CORO_RET(); - } - - coro->cheevo = cheevos_locals.core.cheevos; - coro->cheevo_end = cheevos_locals.core.cheevos + cheevos_locals.core.count; - - for (; coro->cheevo < coro->cheevo_end; coro->cheevo++) - { - for (coro->j = 0 ; coro->j < 2; coro->j++) - { - coro->badge_fullpath[0] = '\0'; - fill_pathname_application_special( - coro->badge_fullpath, - sizeof(coro->badge_fullpath), - APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES); - - if (!path_is_directory(coro->badge_fullpath)) - path_mkdir(coro->badge_fullpath); - CORO_YIELD(); - if (coro->j == 0) - snprintf(coro->badge_name, - sizeof(coro->badge_name), - "%s.png", coro->cheevo->badge); - else - snprintf(coro->badge_name, - sizeof(coro->badge_name), - "%s_lock.png", coro->cheevo->badge); - - fill_pathname_join( - coro->badge_fullpath, - coro->badge_fullpath, - coro->badge_name, - sizeof(coro->badge_fullpath)); - - if (!badge_exists(coro->badge_fullpath)) - { -#ifdef CHEEVOS_LOG_BADGES - CHEEVOS_LOG( - "[CHEEVOS]: downloading badge %s\n", - coro->badge_fullpath); -#endif - snprintf(coro->url, - sizeof(coro->url), - "http://i.retroachievements.org/Badge/%s", - coro->badge_name); - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!filestream_write_file(coro->badge_fullpath, - coro->json, coro->k)) - CHEEVOS_ERR("[CHEEVOS]: error writing badge %s\n", coro->badge_fullpath); - else - free(coro->json); - } - } - } - } - - CORO_RET(); - - /************************************************************************** - * Info Logs in the user at Retro Achievements - *************************************************************************/ - CORO_SUB(LOGIN) - - if (cheevos_locals.token[0]) - CORO_RET(); - - { - char urle_user[64]; - char urle_login[64]; - const char *username = coro ? coro->settings->arrays.cheevos_username : NULL; - const char *login = NULL; - bool via_token = false; - - if (coro) - { - if (string_is_empty(coro->settings->arrays.cheevos_password)) - { - via_token = true; - login = coro->settings->arrays.cheevos_token; - } - else - login = coro->settings->arrays.cheevos_password; - } - else - login = NULL; - - if (string_is_empty(username) || string_is_empty(login)) - { - runloop_msg_queue_push( - "Missing RetroAchievements account information.", - 0, 5 * 60, false); - runloop_msg_queue_push( - "Please fill in your account information in Settings.", - 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: login info not informed.\n"); - CORO_STOP(); - } - - cheevos_url_encode(username, urle_user, sizeof(urle_user)); - cheevos_url_encode(login, urle_login, sizeof(urle_login)); - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=login&u=%s&%c=%s", - urle_user, via_token ? 't' : 'p', urle_login - ); - - coro->url[sizeof(coro->url) - 1] = 0; - } - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to login: %s\n", - coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - char error_response[64]; - char error_message[256]; - - cheevos_get_value( - coro->json, - CHEEVOS_JSON_KEY_ERROR, - error_response, - sizeof(error_response) - ); - - /* No error, continue with login */ - if (string_is_empty(error_response)) - { - int res = cheevos_get_value( - coro->json, - CHEEVOS_JSON_KEY_TOKEN, - cheevos_locals.token, - sizeof(cheevos_locals.token)); - - if ((void*)coro->json) - free((void*)coro->json); - - if (!res) - { - if (coro->settings->bools.cheevos_verbose_enable) - { - char msg[256]; - snprintf(msg, sizeof(msg), - "RetroAchievements: Logged in as \"%s\".", - coro->settings->arrays.cheevos_username); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 3 * 60, false); - } - - /* Save token to config and clear pass on success */ - *coro->settings->arrays.cheevos_password = '\0'; - strncpy( - coro->settings->arrays.cheevos_token, - cheevos_locals.token, sizeof(cheevos_locals.token) - ); - CORO_RET(); - } - } - - if ((void*)coro->json) - free((void*)coro->json); - - /* Site returned error, display it */ - snprintf(error_message, sizeof(error_message), - "RetroAchievements: %s", - error_response); - error_message[sizeof(error_message) - 1] = 0; - runloop_msg_queue_push(error_message, 0, 5 * 60, false); - *coro->settings->arrays.cheevos_token = '\0'; - - CORO_STOP(); - } - - runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: error getting user token.\n"); - - CORO_STOP(); - - /************************************************************************** - * Info Pauses execution for five seconds - *************************************************************************/ - CORO_SUB(DELAY) - - { - retro_time_t t1; - coro->t0 = cpu_features_get_time_usec(); - - do - { - CORO_YIELD(); - t1 = cpu_features_get_time_usec(); - }while ((t1 - coro->t0) < 3000000); - } - - CORO_RET(); - - /************************************************************************** - * Info Makes a HTTP GET request - * Inputs CHEEVOS_VAR_URL - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(HTTP_GET) - - for (coro->k = 0; coro->k < 5; coro->k++) - { - if (coro->k != 0) - CHEEVOS_LOG("[CHEEVOS]: Retrying HTTP request: %u of 5\n", coro->k + 1); - - coro->json = NULL; - coro->conn = net_http_connection_new( - coro->url, "GET", NULL); - - if (!coro->conn) - { - CORO_GOSUB(DELAY); - continue; - } - - /* Don't bother with timeouts here, it's just a string scan. */ - while (!net_http_connection_iterate(coro->conn)) {} - - /* Error finishing the connection descriptor. */ - if (!net_http_connection_done(coro->conn)) - { - net_http_connection_free(coro->conn); - continue; - } - - coro->http = net_http_new(coro->conn); - - /* Error connecting to the endpoint. */ - if (!coro->http) - { - net_http_connection_free(coro->conn); - CORO_GOSUB(DELAY); - continue; - } - - while (!net_http_update(coro->http, NULL, NULL)) - CORO_YIELD(); - - { - size_t length; - uint8_t *data = net_http_data(coro->http, - &length, false); - - if (data) - { - coro->json = (char*)malloc(length + 1); - - if (coro->json) - { - memcpy((void*)coro->json, (void*)data, length); - free(data); - coro->json[length] = 0; - } - - coro->k = (unsigned)length; - net_http_delete(coro->http); - net_http_connection_free(coro->conn); - CORO_RET(); - } - } - - net_http_delete(coro->http); - net_http_connection_free(coro->conn); - } - - CHEEVOS_LOG("[CHEEVOS]: Couldn't connect to server after 5 tries\n"); - CORO_RET(); - - /************************************************************************** - * Info Deactivates the achievements already awarded - * Inputs CHEEVOS_VAR_GAMEID - * Outputs - *************************************************************************/ - CORO_SUB(DEACTIVATE) - -#ifndef CHEEVOS_DONT_DEACTIVATE - CORO_GOSUB(LOGIN); - - /* Deactivate achievements in softcore mode. */ - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=0", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in softcore: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_SOFTCORE)) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in softcore mode.\n"); - else - CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in softcore mode.\n"); - - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in softcore mode.\n"); - - /* Deactivate achievements in hardcore mode. */ - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=1", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in hardcore: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_HARDCORE)) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in hardcore mode.\n"); - else - CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in hardcore mode.\n"); - - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in hardcore mode.\n"); - -#endif - CORO_RET(); - - /************************************************************************** - * Info Posts the "playing" activity to Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs - *************************************************************************/ - CORO_SUB(PLAYING) - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to post the 'playing' activity: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error posting playing activity.\n"); - - CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); - CORO_RET(); - - CORO_LEAVE(); -} - -static void cheevos_task_handler(retro_task_t *task) -{ - coro_t *coro = (coro_t*)task->state; - - if (!coro) - return; - - if (!cheevos_iterate(coro) || task_get_cancelled(task)) - { - task_set_finished(task, true); - - CHEEVOS_LOCK(cheevos_locals.task_lock); - cheevos_locals.task = NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - if (task_get_cancelled(task)) - { - CHEEVOS_LOG("[CHEEVOS]: Load task cancelled\n"); - } - else - { - CHEEVOS_LOG("[CHEEVOS]: Load task finished\n"); - } - - if (coro->data) - free(coro->data); - - if ((void*)coro->path) - free((void*)coro->path); - - free((void*)coro); - } -} - -bool cheevos_load(const void *data) -{ - retro_task_t *task; - const struct retro_game_info *info = NULL; - coro_t *coro = NULL; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - - if (!cheevos_locals.core_supports || !data) - return false; - - coro = (coro_t*)calloc(1, sizeof(*coro)); - - if (!coro) - return false; - - task = (retro_task_t*)calloc(1, sizeof(*task)); - - if (!task) - { - if ((void*)coro) - free((void*)coro); - return false; - } - - CORO_SETUP(); - - info = (const struct retro_game_info*)data; - - if (info->data) - { - coro->len = info->size; - - /* size limit */ - if (coro->len > size_in_megabytes(64)) - coro->len = size_in_megabytes(64); - - coro->data = malloc(coro->len); - - if (!coro->data) - { - if ((void*)task) - free((void*)task); - if ((void*)coro) - free((void*)coro); - return false; - } - - memcpy(coro->data, info->data, coro->len); - coro->path = NULL; - } - else - { - coro->data = NULL; - coro->path = strdup(info->path); - } - - task->handler = cheevos_task_handler; - task->state = (void*)coro; - task->mute = true; - task->callback = NULL; - task->user_data = NULL; - task->progress = 0; - task->title = NULL; - -#ifdef HAVE_THREADS - if (cheevos_locals.task_lock == NULL) - { - cheevos_locals.task_lock = slock_new(); - } -#endif - - CHEEVOS_LOCK(cheevos_locals.task_lock); - cheevos_locals.task = task; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - task_queue_push(task); - - return true; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2018 - Andre Leiradella + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#ifdef HAVE_MENU +#include "../menu/menu_driver.h" +#include "../menu/menu_entries.h" +#endif + +#ifdef HAVE_THREADS +#include +#endif + +#include "badges.h" +#include "cheevos.h" +#include "var.h" +#include "cond.h" + +#include "../file_path_special.h" +#include "../paths.h" +#include "../command.h" +#include "../dynamic.h" +#include "../configuration.h" +#include "../performance_counters.h" +#include "../msg_hash.h" +#include "../retroarch.h" +#include "../core.h" + +#include "../network/net_http_special.h" +#include "../tasks/tasks_internal.h" + +#include "../verbosity.h" + +/* Define this macro to prevent cheevos from being deactivated. */ +#undef CHEEVOS_DONT_DEACTIVATE + +/* Define this macro to log URLs (will log the user token). */ +#undef CHEEVOS_LOG_URLS + +/* Define this macro to dump all cheevos' addresses. */ +#undef CHEEVOS_DUMP_ADDRS + +/* Define this macro to remove HTTP timeouts. */ +#undef CHEEVOS_NO_TIMEOUT + +/* Define this macro to load a JSON file from disk instead of downloading + * from retroachievements.org. */ +#undef CHEEVOS_JSON_OVERRIDE + +/* Define this macro with a string to save the JSON file to disk with + * that name. */ +#undef CHEEVOS_SAVE_JSON + +/* Define this macro to have the password and token logged. THIS WILL DISCLOSE + * THE USER'S PASSWORD, TAKE CARE! */ +#undef CHEEVOS_LOG_PASSWORD + +/* Define this macro to log downloaded badge images. */ +#undef CHEEVOS_LOG_BADGES + +/* C89 wants only int values in enums. */ +#define CHEEVOS_JSON_KEY_GAMEID 0xb4960eecU +#define CHEEVOS_JSON_KEY_ACHIEVEMENTS 0x69749ae1U +#define CHEEVOS_JSON_KEY_ID 0x005973f2U +#define CHEEVOS_JSON_KEY_MEMADDR 0x1e76b53fU +#define CHEEVOS_JSON_KEY_TITLE 0x0e2a9a07U +#define CHEEVOS_JSON_KEY_DESCRIPTION 0xe61a1f69U +#define CHEEVOS_JSON_KEY_POINTS 0xca8fce22U +#define CHEEVOS_JSON_KEY_AUTHOR 0xa804edb8U +#define CHEEVOS_JSON_KEY_MODIFIED 0xdcea4fe6U +#define CHEEVOS_JSON_KEY_CREATED 0x3a84721dU +#define CHEEVOS_JSON_KEY_BADGENAME 0x887685d9U +#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U +#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U +#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U +#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU +#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U +#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU +#define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU +#define CHEEVOS_JSON_KEY_ERROR 0x0d2011cfU + +typedef struct +{ + cheevos_cond_t *conds; + unsigned count; +} cheevos_condset_t; + +typedef struct +{ + cheevos_condset_t *condsets; + unsigned count; +} cheevos_condition_t; + +typedef struct +{ + unsigned id; + const char *title; + const char *description; + const char *author; + const char *badge; + unsigned points; + unsigned dirty; + int active; + int last; + int modified; + + cheevos_condition_t condition; +} cheevo_t; + +typedef struct +{ + cheevo_t *cheevos; + unsigned count; +} cheevoset_t; + +typedef struct +{ + int is_element; + int mode; +} cheevos_deactivate_t; + +typedef struct +{ + unsigned key_hash; + int is_key; + const char *value; + size_t length; +} cheevos_getvalueud_t; + +typedef struct +{ + int in_cheevos; + int in_lboards; + uint32_t field_hash; + unsigned core_count; + unsigned unofficial_count; + unsigned lboard_count; +} cheevos_countud_t; + +typedef struct +{ + const char *string; + size_t length; +} cheevos_field_t; + +typedef struct +{ + int in_cheevos; + int in_lboards; + int is_console_id; + unsigned core_count; + unsigned unofficial_count; + unsigned lboard_count; + + cheevos_field_t *field; + cheevos_field_t id, memaddr, title, desc, points, author; + cheevos_field_t modified, created, badge, flags, format; +} cheevos_readud_t; + +typedef struct +{ + int label; + const char *name; + const uint32_t *ext_hashes; +} cheevos_finder_t; + +typedef struct +{ + cheevos_var_t var; + double multiplier; + bool compare_next; +} cheevos_term_t; + +typedef struct +{ + cheevos_term_t *terms; + unsigned count; + unsigned compare_count; +} cheevos_expr_t; + +typedef struct +{ + unsigned id; + unsigned format; + const char *title; + const char *description; + int active; + int last_value; + + cheevos_condition_t start; + cheevos_condition_t cancel; + cheevos_condition_t submit; + cheevos_expr_t value; +} cheevos_leaderboard_t; + +typedef struct +{ + retro_task_t* task; +#ifdef HAVE_THREADS + slock_t* task_lock; +#endif + + cheevos_console_t console_id; + bool core_supports; + bool addrs_patched; + int add_buffer; + int add_hits; + + cheevoset_t core; + cheevoset_t unofficial; + cheevos_leaderboard_t *leaderboards; + unsigned lboard_count; + + char token[32]; + + retro_ctx_memory_info_t meminfo[4]; +} cheevos_locals_t; + +typedef struct +{ + uint8_t id[4]; /* NES^Z */ + uint8_t rom_size; + uint8_t vrom_size; + uint8_t rom_type; + uint8_t rom_type2; + uint8_t reserve[8]; +} cheevos_nes_header_t; + +static cheevos_locals_t cheevos_locals = +{ + /* task */ NULL, +#ifdef HAVE_THREADS + /* task_lock */ NULL, +#endif + + /* console_id */ CHEEVOS_CONSOLE_NONE, + /* core_supports */ true, + /* addrs_patched */ false, + /* add_buffer */ 0, + /* add_hits */ 0, + + /* core */ {NULL, 0}, + /* unofficial */ {NULL, 0}, + /* leaderboards */ NULL, + /* lboard_count */ 0, + + /* token */ {0}, + + { + /* meminfo[0] */ {NULL, 0, 0}, + /* meminfo[1] */ {NULL, 0, 0}, + /* meminfo[2] */ {NULL, 0, 0}, + /* meminfo[3] */ {NULL, 0, 0} + } +}; + +bool cheevos_loaded = false; +bool cheevos_hardcore_active = false; +bool cheevos_hardcore_paused = false; +bool cheevos_state_loaded_flag = false; +int cheats_are_enabled = 0; +int cheats_were_enabled = 0; + +#ifdef HAVE_THREADS +#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0) +#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0) +#else +#define CHEEVOS_LOCK(l) +#define CHEEVOS_UNLOCK(l) +#endif + +/***************************************************************************** +Supporting functions. +*****************************************************************************/ + +#ifndef CHEEVOS_VERBOSE + +void cheevos_log(const char *fmt, ...) +{ + (void)fmt; +} + +#endif + +static unsigned size_in_megabytes(unsigned val) +{ + return (val * 1024 * 1024); +} + +#ifdef CHEEVOS_LOG_URLS +static void cheevos_log_url(const char* format, const char* url) +{ +#ifdef CHEEVOS_LOG_PASSWORD + CHEEVOS_LOG(format, url); +#else + char copy[256]; + char* aux = NULL; + char* next = NULL; + + if (!string_is_empty(url)) + strlcpy(copy, url, sizeof(copy)); + + aux = strstr(copy, "?p="); + + if (!aux) + aux = strstr(copy, "&p="); + + if (aux) + { + aux += 3; + next = strchr(aux, '&'); + + if (next) + { + do + { + *aux++ = *next++; + }while (next[-1] != 0); + } + else + *aux = 0; + } + + aux = strstr(copy, "?t="); + + if (!aux) + aux = strstr(copy, "&t="); + + if (aux) + { + aux += 3; + next = strchr(aux, '&'); + + if (next) + { + do + { + *aux++ = *next++; + }while (next[-1] != 0); + } + else + *aux = 0; + } + + CHEEVOS_LOG(format, copy); +#endif +} +#endif + +static uint32_t cheevos_djb2(const char* str, size_t length) +{ + const unsigned char *aux = (const unsigned char*)str; + const unsigned char *end = aux + length; + uint32_t hash = 5381; + + while (aux < end) + hash = (hash << 5) + hash + *aux++; + + return hash; +} + +static int cheevos_getvalue__json_key(void *userdata, + const char *name, size_t length) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud) + ud->is_key = cheevos_djb2(name, length) == ud->key_hash; + return 0; +} + +static int cheevos_getvalue__json_string(void *userdata, + const char *string, size_t length) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key) + { + ud->value = string; + ud->length = length; + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_getvalue__json_boolean(void *userdata, int istrue) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key) + { + if (istrue) + { + ud->value = "true"; + ud->length = 4; + } + else + { + ud->value = "false"; + ud->length = 5; + } + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_getvalue__json_null(void *userdata) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key ) + { + ud->value = "null"; + ud->length = 4; + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_get_value(const char *json, unsigned key_hash, + char *value, size_t length) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_getvalue__json_key, + NULL, + cheevos_getvalue__json_string, + cheevos_getvalue__json_string, /* number */ + cheevos_getvalue__json_boolean, + cheevos_getvalue__json_null + }; + + cheevos_getvalueud_t ud; + + ud.key_hash = key_hash; + ud.is_key = 0; + ud.value = NULL; + ud.length = 0; + *value = 0; + + if ((jsonsax_parse(json, &handlers, (void*)&ud) == JSONSAX_OK) + && ud.value && ud.length < length) + { + if (!string_is_empty(ud.value)) + strlcpy(value, ud.value, ud.length + 1); + return 0; + } + + return -1; +} + +/***************************************************************************** +Count number of achievements in a JSON file. +*****************************************************************************/ + +static int cheevos_count__json_end_array(void *userdata) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + ud->in_cheevos = 0; + ud->in_lboards = 0; + } + + return 0; +} + +static int cheevos_count__json_key(void *userdata, + const char *name, size_t length) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + ud->field_hash = cheevos_djb2(name, length); + if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS) + ud->in_cheevos = 1; + else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS) + ud->in_lboards = 1; + } + + return 0; +} + +static int cheevos_count__json_number(void *userdata, + const char *number, size_t length) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + if (ud->in_cheevos && ud->field_hash == CHEEVOS_JSON_KEY_FLAGS) + { + long flags = strtol(number, NULL, 10); + + if (flags == 3) + ud->core_count++; /* Core achievements */ + else if (flags == 5) + ud->unofficial_count++; /* Unofficial achievements */ + } + else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID) + ud->lboard_count++; + } + + return 0; +} + +static int cheevos_count_cheevos(const char *json, + unsigned *core_count, unsigned *unofficial_count, + unsigned *lboard_count) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_count__json_end_array, + cheevos_count__json_key, + NULL, + NULL, + cheevos_count__json_number, + NULL, + NULL + }; + + int res; + cheevos_countud_t ud; + ud.in_cheevos = 0; + ud.in_lboards = 0; + ud.core_count = 0; + ud.unofficial_count = 0; + ud.lboard_count = 0; + + res = jsonsax_parse(json, &handlers, (void*)&ud); + + *core_count = ud.core_count; + *unofficial_count = ud.unofficial_count; + *lboard_count = ud.lboard_count; + + return res; +} + +/***************************************************************************** +Parse the MemAddr field. +*****************************************************************************/ + +static unsigned cheevos_count_cond_sets(const char *memaddr) +{ + cheevos_cond_t cond; + unsigned count = 0; + + for (;;) + { + count++; + + for (;;) + { + cheevos_cond_parse(&cond, &memaddr); + + if (*memaddr != '_') + break; + + memaddr++; + } + + if (*memaddr != 'S') + break; + + memaddr++; + } + + return count; +} + +static int cheevos_parse_condition( + cheevos_condition_t *condition, + const char* memaddr) +{ + if (!condition) + return 0; + + condition->count = cheevos_count_cond_sets(memaddr); + + if (condition->count) + { + unsigned set = 0; + const cheevos_condset_t* end = NULL; + cheevos_condset_t *conds = NULL; + cheevos_condset_t *condset = NULL; + cheevos_condset_t *condsets = (cheevos_condset_t*) + calloc(condition->count, sizeof(cheevos_condset_t)); + + (void)conds; + + if (!condsets) + return -1; + + condition->condsets = condsets; + end = condition->condsets + condition->count; + + for (condset = condition->condsets; condset < end; condset++, set++) + { + condset->count = + cheevos_cond_count_in_set(memaddr, set); + condset->conds = NULL; + + CHEEVOS_LOG("[CHEEVOS]: set %p (index=%u)\n", condset, set); + CHEEVOS_LOG("[CHEEVOS]: conds: %u\n", condset->count); + + if (condset->count) + { + cheevos_cond_t *conds = (cheevos_cond_t*) + calloc(condset->count, sizeof(cheevos_cond_t)); + + if (!conds) + { + while (--condset >= condition->condsets) + { + if ((void*)condset->conds) + free((void*)condset->conds); + } + + return -1; + } + + condset->conds = conds; + cheevos_cond_parse_in_set(condset->conds, memaddr, set); + } + } + } + + return 0; +} + +static void cheevos_free_condition(cheevos_condition_t* condition) +{ + unsigned i; + + if (!condition) + return; + + if (condition->condsets) + { + for (i = 0; i < condition->count; i++) + { + if (condition->condsets[i].conds) + { + free(condition->condsets[i].conds); + condition->condsets[i].conds = NULL; + } + } + + if (condition->condsets) + { + free(condition->condsets); + condition->condsets = NULL; + } + } +} + +/***************************************************************************** +Parse the Mem field of leaderboards. +*****************************************************************************/ + +static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem) +{ + unsigned i; + const char *aux; + cheevos_term_t *terms = NULL; + char *end = NULL; + + if (!expr) + return -1; + + expr->count = 1; + expr->compare_count = 1; + + for (aux = mem;; aux++) + { + if (*aux == '"' || *aux == ':') + break; + expr->count += *aux == '_'; + } + + if (expr->count > 0) + terms = (cheevos_term_t*) + calloc(expr->count, sizeof(cheevos_term_t)); + + if (!terms) + return -1; + + expr->terms = terms; + + for (i = 0; i < expr->count; i++) + { + expr->terms[i].compare_next = false; + expr->terms[i].multiplier = 1; + } + + for (i = 0, aux = mem; i < expr->count;) + { + cheevos_var_parse(&expr->terms[i].var, &aux); + + if (*aux != '*') + { + /* expression has no multiplier */ + if (*aux == '_') + { + aux++; + i++; + } + else if (*aux == '$') + { + expr->terms[i].compare_next = true; + expr->compare_count++; + aux++; + i++; + } + + /* no multiplier at end of string */ + else if (*aux == '\0' || *aux == '"' || *aux == ',') + return 0; + + /* invalid character in expression */ + else + { + if (expr->terms) + { + free(expr->terms); + expr->terms = NULL; + } + return -1; + } + } + else + { + if (aux[1] == 'h' || aux[1] == 'H') + expr->terms[i].multiplier = (double)strtol(aux + 2, &end, 16); + else + expr->terms[i].multiplier = strtod(aux + 1, &end); + aux = end; + + if (*aux == '$') + { + aux++; + expr->terms[i].compare_next = true; + expr->compare_count++; + } + else + expr->terms[i].compare_next = false; + + aux++; + i++; + } + } + return 0; +} + +static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem) +{ + lb->start.condsets = NULL; + lb->cancel.condsets = NULL; + lb->submit.condsets = NULL; + lb->value.terms = NULL; + + for (;;) + { + if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->start, mem + 4)) + goto error; + } + else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->cancel, mem + 4)) + goto error; + } + else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->submit, mem + 4)) + goto error; + } + else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':') + { + if (cheevos_parse_expression(&lb->value, mem + 4)) + goto error; + } + + for (mem += 4;; mem++) + { + if (*mem == ':' && mem[1] == ':') + { + mem += 2; + break; + } + else if (*mem == '"') + return 0; + } + } + +error: + cheevos_free_condition(&lb->start); + cheevos_free_condition(&lb->cancel); + cheevos_free_condition(&lb->submit); + if (lb->value.terms) + { + free((void*)lb->value.terms); + lb->value.terms = NULL; + } + return -1; +} + +/***************************************************************************** +Load achievements from a JSON string. +*****************************************************************************/ + +static INLINE const char *cheevos_dupstr(const cheevos_field_t *field) +{ + char *string = (char*)malloc(field->length + 1); + + if (!string) + return NULL; + + memcpy ((void*)string, (void*)field->string, field->length); + string[field->length] = 0; + + return string; +} + +static int cheevos_new_cheevo(cheevos_readud_t *ud) +{ + cheevo_t *cheevo = NULL; + long flags = strtol(ud->flags.string, NULL, 10); + + if (flags == 3) + cheevo = cheevos_locals.core.cheevos + ud->core_count++; + else if (flags == 5) + cheevo = cheevos_locals.unofficial.cheevos + ud->unofficial_count++; + else + return 0; + + cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10); + cheevo->title = cheevos_dupstr(&ud->title); + cheevo->description = cheevos_dupstr(&ud->desc); + cheevo->author = cheevos_dupstr(&ud->author); + cheevo->badge = cheevos_dupstr(&ud->badge); + cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10); + cheevo->dirty = 0; + cheevo->active = CHEEVOS_ACTIVE_SOFTCORE | CHEEVOS_ACTIVE_HARDCORE; + cheevo->last = 1; + cheevo->modified = 0; + + if ( !cheevo->title || + !cheevo->description || + !cheevo->author || + !cheevo->badge) + goto error; + + if (cheevos_parse_condition(&cheevo->condition, ud->memaddr.string)) + goto error; + + return 0; + +error: + if (cheevo->title) + { + free((void*)cheevo->title); + cheevo->title = NULL; + } + if (cheevo->description) + { + free((void*)cheevo->description); + cheevo->description = NULL; + } + if (cheevo->author) + { + free((void*)cheevo->author); + cheevo->author = NULL; + } + if (cheevo->badge) + { + free((void*)cheevo->badge); + cheevo->badge = NULL; + } + return -1; +} + +/***************************************************************************** +Helper functions for displaying leaderboard values. +*****************************************************************************/ + +static void cheevos_format_value(const unsigned value, const unsigned type, + char* formatted_value, size_t formatted_size) +{ + unsigned mins, secs, millis; + + switch(type) + { + case CHEEVOS_FORMAT_VALUE: + snprintf(formatted_value, formatted_size, "%u", value); + break; + + case CHEEVOS_FORMAT_SCORE: + snprintf(formatted_value, formatted_size, + "%06upts", value); + break; + + case CHEEVOS_FORMAT_FRAMES: + mins = value / 3600; + secs = (value % 3600) / 60; + millis = (int) (value % 60) * (10.00 / 6.00); + snprintf(formatted_value, formatted_size, + "%02u:%02u.%02u", mins, secs, millis); + break; + + case CHEEVOS_FORMAT_MILLIS: + mins = value / 6000; + secs = (value % 6000) / 100; + millis = (int) (value % 100); + snprintf(formatted_value, formatted_size, + "%02u:%02u.%02u", mins, secs, millis); + break; + + case CHEEVOS_FORMAT_SECS: + mins = value / 60; + secs = value % 60; + snprintf(formatted_value, formatted_size, + "%02u:%02u", mins, secs); + break; + + default: + snprintf(formatted_value, formatted_size, + "%u (?)", value); + } +} + +unsigned cheevos_parse_format(cheevos_field_t* format) +{ + /* Most likely */ + if (strncmp(format->string, "VALUE", format->length) == 0) + return CHEEVOS_FORMAT_VALUE; + else if (strncmp(format->string, "TIME", format->length) == 0) + return CHEEVOS_FORMAT_FRAMES; + else if (strncmp(format->string, "SCORE", format->length) == 0) + return CHEEVOS_FORMAT_SCORE; + + /* Less likely */ + else if (strncmp(format->string, "MILLISECS", format->length) == 0) + return CHEEVOS_FORMAT_MILLIS; + else if (strncmp(format->string, "TIMESECS", format->length) == 0) + return CHEEVOS_FORMAT_SECS; + + /* Rare (RPS only) */ + else if (strncmp(format->string, "POINTS", format->length) == 0) + return CHEEVOS_FORMAT_SCORE; + else if (strncmp(format->string, "FRAMES", format->length) == 0) + return CHEEVOS_FORMAT_FRAMES; + else + return CHEEVOS_FORMAT_OTHER; +} + +static int cheevos_new_lboard(cheevos_readud_t *ud) +{ + cheevos_leaderboard_t *lboard = NULL; + cheevos_leaderboard_t *ldb = cheevos_locals.leaderboards; + + if (!ldb || !ud) + return -1; + + lboard = ldb + ud->lboard_count++; + + lboard->id = (unsigned)strtol(ud->id.string, NULL, 10); + lboard->format = cheevos_parse_format(&ud->format); + lboard->title = cheevos_dupstr(&ud->title); + lboard->description = cheevos_dupstr(&ud->desc); + + if (!lboard->title || !lboard->description) + goto error; + + if (cheevos_parse_mem(lboard, ud->memaddr.string)) + goto error; + + return 0; + +error: + if ((void*)lboard->title) + free((void*)lboard->title); + if ((void*)lboard->description) + free((void*)lboard->description); + return -1; +} + +static int cheevos_read__json_key( void *userdata, + const char *name, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + int common = ud->in_cheevos || ud->in_lboards; + uint32_t hash = cheevos_djb2(name, length); + ud->field = NULL; + + switch (hash) + { + case CHEEVOS_JSON_KEY_ACHIEVEMENTS: + ud->in_cheevos = 1; + break; + case CHEEVOS_JSON_KEY_LEADERBOARDS: + ud->in_lboards = 1; + break; + case CHEEVOS_JSON_KEY_CONSOLE_ID: + ud->is_console_id = 1; + break; + case CHEEVOS_JSON_KEY_ID: + if (common) + ud->field = &ud->id; + break; + case CHEEVOS_JSON_KEY_MEMADDR: + if (ud->in_cheevos) + ud->field = &ud->memaddr; + break; + case CHEEVOS_JSON_KEY_MEM: + if (ud->in_lboards) + ud->field = &ud->memaddr; + break; + case CHEEVOS_JSON_KEY_TITLE: + if (common) + ud->field = &ud->title; + break; + case CHEEVOS_JSON_KEY_DESCRIPTION: + if (common) + ud->field = &ud->desc; + break; + case CHEEVOS_JSON_KEY_POINTS: + if (ud->in_cheevos) + ud->field = &ud->points; + break; + case CHEEVOS_JSON_KEY_AUTHOR: + if (ud->in_cheevos) + ud->field = &ud->author; + break; + case CHEEVOS_JSON_KEY_MODIFIED: + if (ud->in_cheevos) + ud->field = &ud->modified; + break; + case CHEEVOS_JSON_KEY_CREATED: + if (ud->in_cheevos) + ud->field = &ud->created; + break; + case CHEEVOS_JSON_KEY_BADGENAME: + if (ud->in_cheevos) + ud->field = &ud->badge; + break; + case CHEEVOS_JSON_KEY_FLAGS: + if (ud->in_cheevos) + ud->field = &ud->flags; + break; + case CHEEVOS_JSON_KEY_FORMAT: + if (ud->in_lboards) + ud->field = &ud->format; + break; + default: + break; + } + } + + return 0; +} + +static int cheevos_read__json_string(void *userdata, + const char *string, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud && ud->field) + { + ud->field->string = string; + ud->field->length = length; + } + + return 0; +} + +static int cheevos_read__json_number(void *userdata, + const char *number, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + if (ud->field) + { + ud->field->string = number; + ud->field->length = length; + } + else if (ud->is_console_id) + { + cheevos_locals.console_id = (cheevos_console_t) + strtol(number, NULL, 10); + ud->is_console_id = 0; + } + } + + return 0; +} + +static int cheevos_read__json_end_object(void *userdata) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + if (ud->in_cheevos) + return cheevos_new_cheevo(ud); + if (ud->in_lboards) + return cheevos_new_lboard(ud); + } + + return 0; +} + +static int cheevos_read__json_end_array(void *userdata) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + ud->in_cheevos = 0; + ud->in_lboards = 0; + } + + return 0; +} + +static int cheevos_parse(const char *json) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + cheevos_read__json_end_object, + NULL, + cheevos_read__json_end_array, + cheevos_read__json_key, + NULL, + cheevos_read__json_string, + cheevos_read__json_number, + NULL, + NULL + }; + + cheevos_readud_t ud; + unsigned core_count, unofficial_count, lboard_count; + /* Count the number of achievements in the JSON file. */ + int res = cheevos_count_cheevos(json, &core_count, &unofficial_count, + &lboard_count); + + if (res != JSONSAX_OK) + return -1; + + /* Allocate the achievements. */ + + cheevos_locals.core.cheevos = (cheevo_t*) + calloc(core_count, sizeof(cheevo_t)); + cheevos_locals.core.count = core_count; + + cheevos_locals.unofficial.cheevos = (cheevo_t*) + calloc(unofficial_count, sizeof(cheevo_t)); + cheevos_locals.unofficial.count = unofficial_count; + + cheevos_locals.leaderboards = (cheevos_leaderboard_t*) + calloc(lboard_count, sizeof(cheevos_leaderboard_t)); + cheevos_locals.lboard_count = lboard_count; + + if ( !cheevos_locals.core.cheevos || + !cheevos_locals.unofficial.cheevos || + !cheevos_locals.leaderboards) + { + if ((void*)cheevos_locals.core.cheevos) + free((void*)cheevos_locals.core.cheevos); + if ((void*)cheevos_locals.unofficial.cheevos) + free((void*)cheevos_locals.unofficial.cheevos); + if ((void*)cheevos_locals.leaderboards) + free((void*)cheevos_locals.leaderboards); + cheevos_locals.core.count = cheevos_locals.unofficial.count = + cheevos_locals.lboard_count = 0; + + return -1; + } + + /* Load the achievements. */ + ud.in_cheevos = 0; + ud.in_lboards = 0; + ud.is_console_id = 0; + ud.field = NULL; + ud.core_count = 0; + ud.unofficial_count = 0; + ud.lboard_count = 0; + + if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK) + goto error; + + return 0; + +error: + cheevos_unload(); + + return -1; +} + +/***************************************************************************** +Test all the achievements (call once per frame). +*****************************************************************************/ + +static int cheevos_test_condition(cheevos_cond_t *cond) +{ + unsigned sval = 0; + unsigned tval = 0; + + if (!cond) + return 0; + + sval = cheevos_var_get_value(&cond->source) + + cheevos_locals.add_buffer; + tval = cheevos_var_get_value(&cond->target); + + switch (cond->op) + { + case CHEEVOS_COND_OP_EQUALS: + return (sval == tval); + case CHEEVOS_COND_OP_LESS_THAN: + return (sval < tval); + case CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL: + return (sval <= tval); + case CHEEVOS_COND_OP_GREATER_THAN: + return (sval > tval); + case CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL: + return (sval >= tval); + case CHEEVOS_COND_OP_NOT_EQUAL_TO: + return (sval != tval); + default: + break; + } + + return 1; +} + +static int cheevos_test_pause_cond_set(const cheevos_condset_t *condset, + int *dirty_conds, int *reset_conds, int process_pause) +{ + int cond_valid = 0; + int set_valid = 1; /* must start true so AND logic works */ + cheevos_cond_t *cond = NULL; + const cheevos_cond_t *end = condset->conds + condset->count; + + cheevos_locals.add_buffer = 0; + cheevos_locals.add_hits = 0; + + for (cond = condset->conds; cond < end; cond++) + { + if (cond->pause != process_pause) + continue; + + if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE) + { + cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source); + continue; + } + + if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE) + { + cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source); + continue; + } + + if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS) + { + if (cheevos_test_condition(cond)) + { + cond->curr_hits++; + *dirty_conds = 1; + } + + cheevos_locals.add_hits += cond->curr_hits; + continue; + } + + /* always evaluate the condition to ensure delta values get tracked correctly */ + cond_valid = cheevos_test_condition(cond); + + /* if the condition has a target hit count that has already been met, + * it's automatically true, even if not currently true. */ + if ( (cond->req_hits != 0) && + (cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits) + { + cond_valid = 1; + } + else if (cond_valid) + { + cond->curr_hits++; + *dirty_conds = 1; + + /* Process this logic, if this condition is true: */ + if (cond->req_hits == 0) + ; /* Not a hit-based requirement: ignore any additional logic! */ + else if ((cond->curr_hits + cheevos_locals.add_hits) < cond->req_hits) + cond_valid = 0; /* HitCount target has not yet been met, condition is not yet valid. */ + } + + cheevos_locals.add_buffer = 0; + cheevos_locals.add_hits = 0; + + if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) + { + /* as soon as we find a PauseIf that evaluates to true, + * stop processing the rest of the group. */ + if (cond_valid) + return 1; + + /* if we make it to the end of the function, make sure we are + * indicating nothing matched. if we do find a later PauseIf match, + * it'll automatically return true via the previous condition. */ + set_valid = 0; + + if (cond->req_hits == 0) + { + /* PauseIf didn't evaluate true, and doesn't have a HitCount, + * reset the HitCount to indicate the condition didn't match. */ + if (cond->curr_hits != 0) + { + cond->curr_hits = 0; + *dirty_conds = 1; + } + } + else + { + /* PauseIf has a HitCount that hasn't been met, ignore it for now. */ + } + } + else if (cond->type == CHEEVOS_COND_TYPE_RESET_IF) + { + if (cond_valid) + { + *reset_conds = 1; /* Resets all hits found so far */ + set_valid = 0; /* Cannot be valid if we've hit a reset condition. */ + } + } + else /* Sequential or non-sequential? */ + set_valid &= cond_valid; + } + + return set_valid; +} + +static int cheevos_test_cond_set(const cheevos_condset_t *condset, + int *dirty_conds, int *reset_conds) +{ + int in_pause = 0; + int has_pause = 0; + cheevos_cond_t *cond = NULL; + + if (!condset) + return 1; /* important: empty group must evaluate true */ + + /* the ints below are used for Pause conditions and their dependent AddSource/AddHits. */ + + /* this loop needs to go backwards to check AddSource/AddHits */ + cond = condset->conds + condset->count - 1; + for (; cond >= condset->conds; cond--) + { + if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) + { + has_pause = 1; + in_pause = 1; + cond->pause = 1; + } + else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE || + cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE || + cond->type == CHEEVOS_COND_TYPE_ADD_HITS) + { + cond->pause = in_pause; + } + else + { + in_pause = 0; + cond->pause = 0; + } + } + + if (has_pause) + { /* one or more Pause conditions exists, if any of them are true, + * stop processing this group. */ + if (cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 1)) + return 0; + } + + /* process the non-Pause conditions to see if the group is true */ + return cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 0); +} + +static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas) +{ + int dirty = 0; + const cheevos_cond_t *end = NULL; + + if (!condset) + return 0; + + end = condset->conds + condset->count; + + if (deltas) + { + cheevos_cond_t *cond = NULL; + for (cond = condset->conds; cond < end; cond++) + { + dirty |= cond->curr_hits != 0; + + cond->curr_hits = 0; + + cond->source.previous = cond->source.value; + cond->target.previous = cond->target.value; + } + } + else + { + cheevos_cond_t *cond = NULL; + for (cond = condset->conds; cond < end; cond++) + { + dirty |= cond->curr_hits != 0; + cond->curr_hits = 0; + } + } + + return dirty; +} + +static int cheevos_test_cheevo(cheevo_t *cheevo) +{ + int dirty_conds = 0; + int reset_conds = 0; + int ret_val = 0; + int ret_val_sub_cond = 0; + cheevos_condset_t *condset = NULL; + cheevos_condset_t *end = NULL; + + if (!cheevo) + return 0; + + ret_val_sub_cond = cheevo->condition.count == 1; + condset = cheevo->condition.condsets; + + if (!condset) + return 0; + + end = condset + cheevo->condition.count; + + if (condset < end) + { + ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds); + condset++; + } + + while (condset < end) + { + ret_val_sub_cond |= cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + if (dirty_conds) + cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; + + if (reset_conds) + { + int dirty = 0; + + for (condset = cheevo->condition.condsets; condset < end; condset++) + dirty |= cheevos_reset_cond_set(condset, 0); + + if (dirty) + cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; + } + + return (ret_val && ret_val_sub_cond); +} + +static void cheevos_url_encode(const char *str, char *encoded, size_t len) +{ + if (!str) + return; + + while (*str) + { + if ( isalnum((unsigned char)*str) || *str == '-' + || *str == '_' || *str == '.' + || *str == '~') + { + if (len >= 2) + { + *encoded++ = *str++; + len--; + } + else + break; + } + else + { + if (len >= 4) + { + snprintf(encoded, len, "%%%02x", (uint8_t)*str); + encoded += 3; + str++; + len -= 3; + } + else + break; + } + } + + *encoded = 0; +} + +static void cheevos_make_unlock_url(const cheevo_t *cheevo, + char* url, size_t url_size) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + snprintf( + url, url_size, + "http://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d", + settings->arrays.cheevos_username, + cheevos_locals.token, + cheevo->id, + settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused ? 1 : 0 + ); + + url[url_size - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to award the cheevo: %s\n", url); +#endif +} + +static void cheevos_unlocked(void *task_data, void *user_data, + const char *error) +{ + cheevo_t *cheevo = (cheevo_t *)user_data; + + if (!error) + { + CHEEVOS_LOG("[CHEEVOS]: awarded achievement %u.\n", cheevo->id); + } + else + { + char url[256]; + url[0] = '\0'; + + CHEEVOS_ERR("[CHEEVOS]: error awarding achievement %u, retrying...\n", cheevo->id); + + cheevos_make_unlock_url(cheevo, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, cheevos_unlocked, cheevo); + } +} + +static void cheevos_test_cheevo_set(const cheevoset_t *set) +{ + settings_t *settings = config_get_ptr(); + int mode = CHEEVOS_ACTIVE_SOFTCORE; + cheevo_t *cheevo = NULL; + const cheevo_t *end = NULL; + + if (!set) + return; + + end = set->cheevos + set->count; + + if (settings && settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + mode = CHEEVOS_ACTIVE_HARDCORE; + + for (cheevo = set->cheevos; cheevo < end; cheevo++) + { + if (cheevo->active & mode) + { + int valid = cheevos_test_cheevo(cheevo); + + if (cheevo->last) + { + cheevos_condset_t* condset = cheevo->condition.condsets; + const cheevos_condset_t* end = cheevo->condition.condsets + + cheevo->condition.count; + + for (; condset < end; condset++) + cheevos_reset_cond_set(condset, 0); + } + else if (valid) + { + char msg[256]; + char url[256]; + msg[0] = url[0] = '\0'; + + cheevo->active &= ~mode; + + if (mode == CHEEVOS_ACTIVE_HARDCORE) + cheevo->active &= ~CHEEVOS_ACTIVE_SOFTCORE; + + CHEEVOS_LOG("[CHEEVOS]: awarding cheevo %u: %s (%s).\n", + cheevo->id, cheevo->title, cheevo->description); + + snprintf(msg, sizeof(msg), "Achievement Unlocked: %s", + cheevo->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false); + + cheevos_make_unlock_url(cheevo, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, + cheevos_unlocked, cheevo); + + if (settings && settings->bools.cheevos_auto_screenshot) + { + char shotname[256]; + + snprintf(shotname, sizeof(shotname), "%s/%s-cheevo-%u", + settings->paths.directory_screenshot, + path_basename(path_get(RARCH_PATH_BASENAME)), + cheevo->id); + shotname[sizeof(shotname) - 1] = '\0'; + + if (take_screenshot(shotname, true, + video_driver_cached_frame_has_valid_framebuffer(), false, true)) + CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); + else + CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); + } + } + + cheevo->last = valid; + } + } +} + +static int cheevos_test_lboard_condition(const cheevos_condition_t* condition) +{ + int dirty_conds = 0; + int reset_conds = 0; + int ret_val = 0; + int ret_val_sub_cond = 0; + cheevos_condset_t *condset = NULL; + const cheevos_condset_t *end = NULL; + + if (!condition) + return 0; + + ret_val_sub_cond = condition->count == 1; + condset = condition->condsets; + end = condset + condition->count; + + if (condset < end) + { + ret_val = cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + while (condset < end) + { + ret_val_sub_cond |= cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + if (reset_conds) + { + for (condset = condition->condsets; condset < end; condset++) + cheevos_reset_cond_set(condset, 0); + } + + return (ret_val && ret_val_sub_cond); +} + +static int cheevos_expr_value(cheevos_expr_t* expr) +{ + unsigned i; + int values[16]; + /* Separate possible values with '$' operator, submit the largest */ + unsigned current_value = 0; + cheevos_term_t* term = NULL; + + if (!expr) + return 0; + + term = expr->terms; + + if (!term) + return 0; + + if (expr->compare_count >= ARRAY_SIZE(values)) + { + CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", expr->compare_count); + return 0; + } + + memset(values, 0, sizeof values); + + for (i = expr->count; i != 0; i--, term++) + { + if (current_value >= ARRAY_SIZE(values)) + { + CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", current_value); + return 0; + } + + values[current_value] += + cheevos_var_get_value(&term->var) * term->multiplier; + + if (term->compare_next) + current_value++; + } + + if (expr->compare_count > 1) + { + unsigned j; + int maximum = values[0]; + + for (j = 1; j < expr->compare_count; j++) + maximum = values[j] > maximum ? values[j] : maximum; + + return maximum; + } + else + return values[0]; +} + +static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, + char* url, size_t url_size) +{ + MD5_CTX ctx; + uint8_t hash[16]; + char signature[64]; + settings_t *settings = config_get_ptr(); + + hash[0] = '\0'; + + snprintf(signature, sizeof(signature), "%u%s%u", lboard->id, + settings->arrays.cheevos_username, + lboard->id); + + MD5_Init(&ctx); + MD5_Update(&ctx, (void*)signature, strlen(signature)); + MD5_Final(hash, &ctx); + + snprintf( + url, url_size, + "http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d" + "&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + settings->arrays.cheevos_username, + cheevos_locals.token, + lboard->id, + lboard->last_value, + hash[ 0], hash[ 1], hash[ 2], hash[ 3], + hash[ 4], hash[ 5], hash[ 6], hash[ 7], + hash[ 8], hash[ 9], hash[10], hash[11], + hash[12], hash[13], hash[14], hash[15] + ); + + url[url_size - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to submit the leaderboard: %s\n", url); +#endif +} + +static void cheevos_lboard_submit(void *task_data, void *user_data, + const char *error) +{ + cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; + + if (!lboard) + return; + + if (!error) + { + CHEEVOS_ERR("[CHEEVOS]: error submitting leaderboard %u\n", lboard->id); + return; + } + + CHEEVOS_LOG("[CHEEVOS]: submitted leaderboard %u.\n", lboard->id); +} + +static void cheevos_test_leaderboards(void) +{ + unsigned i; + cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards; + + if (!lboard) + return; + + for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++) + { + if (lboard->active) + { + int value = cheevos_expr_value(&lboard->value); + + if (value != lboard->last_value) + { + CHEEVOS_LOG("[CHEEVOS]: value lboard %s %u\n", + lboard->title, value); + lboard->last_value = value; + } + + if (cheevos_test_lboard_condition(&lboard->submit)) + { + lboard->active = 0; + + /* failsafe for improper LBs */ + if (value == 0) + { + CHEEVOS_LOG("[CHEEVOS]: error: lboard %s tried to submit 0\n", + lboard->title); + runloop_msg_queue_push("Leaderboard attempt cancelled!", + 0, 2 * 60, false); + } + else + { + char url[256]; + char msg[256]; + char formatted_value[16]; + + cheevos_make_lboard_url(lboard, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, + cheevos_lboard_submit, lboard); + CHEEVOS_LOG("[CHEEVOS]: submit lboard %s\n", lboard->title); + + cheevos_format_value(value, lboard->format, + formatted_value, sizeof(formatted_value)); + snprintf(msg, sizeof(msg), "Submitted %s for %s", + formatted_value, lboard->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + } + } + + if (cheevos_test_lboard_condition(&lboard->cancel)) + { + CHEEVOS_LOG("[CHEEVOS]: cancel lboard %s\n", lboard->title); + lboard->active = 0; + runloop_msg_queue_push("Leaderboard attempt cancelled!", + 0, 2 * 60, false); + } + } + else + { + if (cheevos_test_lboard_condition(&lboard->start)) + { + char msg[256]; + + CHEEVOS_LOG("[CHEEVOS]: start lboard %s\n", lboard->title); + lboard->active = 1; + lboard->last_value = -1; + + snprintf(msg, sizeof(msg), + "Leaderboard Active: %s", lboard->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + runloop_msg_queue_push(lboard->description, 0, 3*60, false); + } + } + } +} + +/***************************************************************************** +Free the loaded achievements. +*****************************************************************************/ + +static void cheevos_free_condset(const cheevos_condset_t *set) +{ + if (set && set->conds) + free((void*)set->conds); +} + +static void cheevos_free_cheevo(const cheevo_t *cheevo) +{ + if (!cheevo) + return; + + if (cheevo->title) + free((void*)cheevo->title); + if (cheevo->description) + free((void*)cheevo->description); + if (cheevo->author) + free((void*)cheevo->author); + if (cheevo->badge) + free((void*)cheevo->badge); + cheevos_free_condset(cheevo->condition.condsets); +} + +static void cheevos_free_cheevo_set(const cheevoset_t *set) +{ + const cheevo_t *cheevo = NULL; + const cheevo_t *end = NULL; + + if (!set) + return; + + cheevo = set->cheevos; + end = cheevo + set->count; + + while (cheevo < end) + cheevos_free_cheevo(cheevo++); + + if (set->cheevos) + free((void*)set->cheevos); +} + +#ifndef CHEEVOS_DONT_DEACTIVATE +static int cheevos_deactivate__json_index(void *userdata, unsigned int index) +{ + cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; + + if (ud) + ud->is_element = 1; + + return 0; +} + +static int cheevos_deactivate__json_number(void *userdata, + const char *number, size_t length) +{ + long id; + int found; + cheevo_t* cheevo = NULL; + const cheevo_t* end = NULL; + cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; + + if (ud && ud->is_element) + { + ud->is_element = 0; + id = strtol(number, NULL, 10); + found = 0; + cheevo = cheevos_locals.core.cheevos; + end = cheevo + cheevos_locals.core.count; + + for (; cheevo < end; cheevo++) + { + if (cheevo->id == (unsigned)id) + { + cheevo->active &= ~ud->mode; + found = 1; + break; + } + } + + if (!found) + { + cheevo = cheevos_locals.unofficial.cheevos; + end = cheevo + cheevos_locals.unofficial.count; + + for (; cheevo < end; cheevo++) + { + if (cheevo->id == (unsigned)id) + { + cheevo->active &= ~ud->mode; + found = 1; + break; + } + } + } + + if (found) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked cheevo %u (%s).\n", + cheevo->id, cheevo->title); + else + CHEEVOS_ERR("[CHEEVOS]: unknown cheevo to deactivate: %u.\n", id); + } + + return 0; +} + +static int cheevos_deactivate_unlocks(const char* json, unsigned mode) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_deactivate__json_index, + NULL, + cheevos_deactivate__json_number, + NULL, + NULL + }; + + cheevos_deactivate_t ud; + + ud.is_element = 0; + ud.mode = mode; + return jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK; +} +#endif + +void cheevos_reset_game(void) +{ + cheevo_t *end = NULL; + cheevo_t *cheevo = cheevos_locals.core.cheevos; + + if (!cheevo) + return; + + end = cheevo + cheevos_locals.core.count; + + for (; cheevo < end; cheevo++) + cheevo->last = 1; + + cheevo = cheevos_locals.unofficial.cheevos; + end = cheevo + cheevos_locals.unofficial.count; + + for (; cheevo < end; cheevo++) + cheevo->last = 1; +} + +void cheevos_populate_menu(void *data) +{ +#ifdef HAVE_MENU + unsigned i = 0; + unsigned items_found = 0; + settings_t *settings = config_get_ptr(); + menu_displaylist_info_t *info = (menu_displaylist_info_t*)data; + cheevo_t *end = NULL; + cheevo_t *cheevo = cheevos_locals.core.cheevos; + end = cheevo + cheevos_locals.core.count; + + if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable + && cheevos_loaded) + { + if (!cheevos_hardcore_paused) + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE), + msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE), + MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE, + MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0); + else + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME), + msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME), + MENU_ENUM_LABEL_ACHIEVEMENT_RESUME, + MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0); + } + + if (cheevo) + { + for (i = 0; cheevo < end; i++, cheevo++) + { + if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); + } + else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + else + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + items_found++; + } + } + + cheevo = cheevos_locals.unofficial.cheevos; + + if (cheevo && settings->bools.cheevos_test_unofficial) + { + end = cheevo + cheevos_locals.unofficial.count; + + for (i = items_found; cheevo < end; i++, cheevo++) + { + if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); + } + else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + else + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + items_found++; + } + } + + if (items_found == 0) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0); + } +#endif +} + +bool cheevos_get_description(cheevos_ctx_desc_t *desc) +{ + if (!desc) + return false; + + if (cheevos_loaded) + { + cheevo_t *cheevos = cheevos_locals.core.cheevos; + + if (!cheevos) + return false; + + if (desc->idx >= cheevos_locals.core.count) + { + cheevos = cheevos_locals.unofficial.cheevos; + desc->idx -= cheevos_locals.core.count; + } + + if (!string_is_empty(cheevos[desc->idx].description)) + strlcpy(desc->s, cheevos[desc->idx].description, desc->len); + } + else + *desc->s = 0; + + return true; +} + +bool cheevos_apply_cheats(bool *data_bool) +{ + cheats_are_enabled = *data_bool; + cheats_were_enabled |= cheats_are_enabled; + + return true; +} + +bool cheevos_unload(void) +{ + bool running; + CHEEVOS_LOCK(cheevos_locals.task_lock); + running = cheevos_locals.task != NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + if (running) + { + CHEEVOS_LOG("[CHEEVOS]: Asked the load thread to terminate\n"); + task_queue_cancel_task(cheevos_locals.task); + +#ifdef HAVE_THREADS + do + { + CHEEVOS_LOCK(cheevos_locals.task_lock); + running = cheevos_locals.task != NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + } + while (running); +#endif + } + + if (cheevos_loaded) + { + cheevos_free_cheevo_set(&cheevos_locals.core); + cheevos_free_cheevo_set(&cheevos_locals.unofficial); + } + + cheevos_locals.core.cheevos = NULL; + cheevos_locals.unofficial.cheevos = NULL; + cheevos_locals.core.count = 0; + cheevos_locals.unofficial.count = 0; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + + return true; +} + +bool cheevos_toggle_hardcore_mode(void) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return false; + + /* reset and deinit rewind to avoid cheat the score */ + if (settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + { + const char *msg = msg_hash_to_str( + MSG_CHEEVOS_HARDCORE_MODE_ENABLE); + + /* send reset core cmd to avoid any user + * savestate previusly loaded. */ + command_event(CMD_EVENT_RESET, NULL); + + if (settings->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_DEINIT, NULL); + + CHEEVOS_LOG("%s\n", msg); + runloop_msg_queue_push(msg, 0, 3 * 60, true); + } + else + { + if (settings->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_INIT, NULL); + } + + return true; +} + +static void cheevos_patch_addresses(cheevoset_t* set) +{ + unsigned i; + cheevo_t* cheevo = NULL; + + if (!set) + return; + + cheevo = set->cheevos; + + if (!cheevo) + return; + + for (i = set->count; i != 0; i--, cheevo++) + { + unsigned j; + cheevos_condset_t* condset = cheevo->condition.condsets; + + for (j = cheevo->condition.count; j != 0; j--, condset++) + { + unsigned k; + cheevos_cond_t* cond = condset->conds; + + for (k = condset->count; k != 0; k--, cond++) + { + switch (cond->source.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->source, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + cond->source.bank_id + 1, cond->source.value); +#endif + break; + + default: + break; + } + + switch (cond->target.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->target, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", + cond->target.bank_id + 1, cond->target.value); +#endif + break; + + default: + break; + } + } + } + } +} + +static void cheevos_patch_lb_conditions(cheevos_condition_t* condition) +{ + unsigned i; + cheevos_condset_t* condset = NULL; + + if (!condition) + return; + + condset = condition->condsets; + + for (i = condition->count; i != 0; i--, condset++) + { + unsigned j; + cheevos_cond_t* cond = condset->conds; + + for (j = condset->count; j != 0; j--, cond++) + { + switch (cond->source.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->source, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + cond->source.bank_id + 1, cond->source.value); +#endif + break; + default: + break; + } + switch (cond->target.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->target, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", + cond->target.bank_id + 1, cond->target.value); +#endif + break; + default: + break; + } + } + } +} + +static void cheevos_patch_lb_expressions(cheevos_expr_t* expression) +{ + unsigned i; + cheevos_term_t* term = NULL; + + if (!expression) + return; + + term = expression->terms; + + for (i = expression->count; i != 0; i--, term++) + { + switch (term->var.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&term->var, cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + term->var.bank_id + 1, term->var.value); +#endif + break; + default: + break; + } + } +} + +static void cheevos_patch_lbs(cheevos_leaderboard_t *leaderboard) +{ + unsigned i; + + for (i = 0; i < cheevos_locals.lboard_count; i++) + { + cheevos_condition_t *start = &leaderboard[i].start; + cheevos_condition_t *cancel = &leaderboard[i].cancel; + cheevos_condition_t *submit = &leaderboard[i].submit; + cheevos_expr_t *value = &leaderboard[i].value; + + cheevos_patch_lb_conditions(start); + cheevos_patch_lb_conditions(cancel); + cheevos_patch_lb_conditions(submit); + cheevos_patch_lb_expressions(value); + } +} + +void cheevos_test(void) +{ + settings_t *settings = config_get_ptr(); + + if (!cheevos_locals.addrs_patched) + { + cheevos_patch_addresses(&cheevos_locals.core); + cheevos_patch_addresses(&cheevos_locals.unofficial); + cheevos_patch_lbs(cheevos_locals.leaderboards); + + cheevos_locals.addrs_patched = true; + } + + cheevos_test_cheevo_set(&cheevos_locals.core); + + if (settings) + { + if (settings->bools.cheevos_test_unofficial) + cheevos_test_cheevo_set(&cheevos_locals.unofficial); + + if (settings->bools.cheevos_hardcore_mode_enable && + settings->bools.cheevos_leaderboards_enable && + !cheevos_hardcore_paused) + cheevos_test_leaderboards(); + } +} + +bool cheevos_set_cheats(void) +{ + cheats_were_enabled = cheats_are_enabled; + return true; +} + +void cheevos_set_support_cheevos(bool state) +{ + cheevos_locals.core_supports = state; +} + +bool cheevos_get_support_cheevos(void) +{ + return cheevos_locals.core_supports; +} + +cheevos_console_t cheevos_get_console(void) +{ + return cheevos_locals.console_id; +} + +#include "coro.h" + +/* Uncomment the following two lines to debug cheevos_iterate, this will + * disable the coroutine yielding. + * + * The code is very easy to understand. It's meant to be like BASIC: + * CORO_GOTO will jump execution to another label, CORO_GOSUB will + * call another label, and CORO_RET will return from a CORO_GOSUB. + * + * This coroutine code is inspired in a very old pure C implementation + * that runs everywhere: + * + * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + */ +/*#undef CORO_YIELD +#define CORO_YIELD()*/ + +typedef struct +{ + /* variables used in the co-routine */ + char badge_name[16]; + char url[256]; + char badge_basepath[PATH_MAX_LENGTH]; + char badge_fullpath[PATH_MAX_LENGTH]; + unsigned char hash[16]; + bool round; + unsigned gameid; + unsigned i; + unsigned j; + unsigned k; + size_t bytes; + size_t count; + size_t offset; + size_t len; + size_t size; + MD5_CTX md5; + cheevos_nes_header_t header; + retro_time_t t0; + struct retro_system_info sysinfo; + void *data; + char *json; + const char *path; + const char *ext; + intfstream_t *stream; + cheevo_t *cheevo; + settings_t *settings; + struct http_connection_t *conn; + struct http_t *http; + const cheevo_t *cheevo_end; + + /* co-routine required fields */ + CORO_FIELDS +} coro_t; + +enum +{ + /* Negative values because CORO_SUB generates positive values */ + SNES_MD5 = -1, + GENESIS_MD5 = -2, + LYNX_MD5 = -3, + NES_MD5 = -4, + GENERIC_MD5 = -5, + FILENAME_MD5 = -6, + EVAL_MD5 = -7, + FILL_MD5 = -8, + GET_GAMEID = -9, + GET_CHEEVOS = -10, + GET_BADGES = -11, + LOGIN = -12, + HTTP_GET = -13, + DEACTIVATE = -14, + PLAYING = -15, + DELAY = -16 +}; + +static int cheevos_iterate(coro_t *coro) +{ + ssize_t num_read = 0; + size_t to_read = 4096; + uint8_t *buffer = NULL; + const char *end = NULL; + + static const uint32_t genesis_exts[] = + { + 0x0b888feeU, /* mdx */ + 0x005978b6U, /* md */ + 0x0b88aa89U, /* smd */ + 0x0b88767fU, /* gen */ + 0x0b8861beU, /* bin */ + 0x0b886782U, /* cue */ + 0x0b8880d0U, /* iso */ + 0x0b88aa98U, /* sms */ + 0x005977f3U, /* gg */ + 0x0059797fU, /* sg */ + 0 + }; + + static const uint32_t snes_exts[] = + { + 0x0b88aa88U, /* smc */ + 0x0b8872bbU, /* fig */ + 0x0b88a9a1U, /* sfc */ + 0x0b887623U, /* gd3 */ + 0x0b887627U, /* gd7 */ + 0x0b886bf3U, /* dx2 */ + 0x0b886312U, /* bsx */ + 0x0b88abd2U, /* swc */ + 0 + }; + + static const uint32_t lynx_exts[] = + { + 0x0b888cf7U, /* lnx */ + 0 + }; + + static cheevos_finder_t finders[] = + { + {SNES_MD5, "SNES (8Mb padding)", snes_exts}, + {GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts}, + {LYNX_MD5, "Atari Lynx (only first 512 bytes)", lynx_exts}, + {NES_MD5, "NES (discards VROM)", NULL}, + {GENERIC_MD5, "Generic (plain content)", NULL}, + {FILENAME_MD5, "Generic (filename)", NULL} + }; + + CORO_ENTER(); + + + + cheevos_locals.addrs_patched = false; + + coro->settings = config_get_ptr(); + + cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM; + core_get_memory(&cheevos_locals.meminfo[0]); + + cheevos_locals.meminfo[1].id = RETRO_MEMORY_SAVE_RAM; + core_get_memory(&cheevos_locals.meminfo[1]); + + cheevos_locals.meminfo[2].id = RETRO_MEMORY_VIDEO_RAM; + core_get_memory(&cheevos_locals.meminfo[2]); + + cheevos_locals.meminfo[3].id = RETRO_MEMORY_RTC; + core_get_memory(&cheevos_locals.meminfo[3]); + + CHEEVOS_LOG("[CHEEVOS]: system RAM: %p %u\n", + cheevos_locals.meminfo[0].data, + cheevos_locals.meminfo[0].size); + CHEEVOS_LOG("[CHEEVOS]: save RAM: %p %u\n", + cheevos_locals.meminfo[1].data, + cheevos_locals.meminfo[1].size); + CHEEVOS_LOG("[CHEEVOS]: video RAM: %p %u\n", + cheevos_locals.meminfo[2].data, + cheevos_locals.meminfo[2].size); + CHEEVOS_LOG("[CHEEVOS]: RTC: %p %u\n", + cheevos_locals.meminfo[3].data, + cheevos_locals.meminfo[3].size); + + /* Bail out if cheevos are disabled. + * But set the above anyways, + * command_read_ram needs it. */ + if (!coro->settings->bools.cheevos_enable) + CORO_STOP(); + + /* Load the content into memory, or copy it + * over to our own buffer */ + if (!coro->data) + { + coro->stream = intfstream_open_file( + coro->path, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!coro->stream) + CORO_STOP(); + + CORO_YIELD(); + coro->len = 0; + coro->count = intfstream_get_size(coro->stream); + + /* size limit */ + if (coro->count > size_in_megabytes(64)) + coro->count = size_in_megabytes(64); + + coro->data = malloc(coro->count); + + if (!coro->data) + { + intfstream_close(coro->stream); + free(coro->stream); + CORO_STOP(); + } + + for (;;) + { + buffer = (uint8_t*)coro->data + coro->len; + to_read = 4096; + + if (to_read > coro->count) + to_read = coro->count; + + num_read = intfstream_read(coro->stream, + (void*)buffer, to_read); + + if (num_read <= 0) + break; + + coro->len += num_read; + coro->count -= num_read; + + if (coro->count == 0) + break; + + CORO_YIELD(); + } + + intfstream_close(coro->stream); + free(coro->stream); + } + + /* Use the supported extensions as a hint + * to what method we should use. */ + core_get_system_info(&coro->sysinfo); + + for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) + { + if (finders[coro->i].ext_hashes) + { + coro->ext = coro->sysinfo.valid_extensions; + + while (coro->ext) + { + unsigned hash; + end = strchr(coro->ext, '|'); + + if (end) + { + hash = cheevos_djb2( + coro->ext, end - coro->ext); + coro->ext = end + 1; + } + else + { + hash = cheevos_djb2( + coro->ext, strlen(coro->ext)); + coro->ext = NULL; + } + + for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++) + { + if (finders[coro->i].ext_hashes[coro->j] == hash) + { + CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", + finders[coro->i].name); + + /* + * Inputs: CHEEVOS_VAR_INFO + * Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0 + */ + CORO_GOSUB(finders[coro->i].label); + + if (coro->gameid != 0) + goto found; + + coro->ext = NULL; /* force next finder */ + break; + } + } + } + } + } + + for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) + { + if (finders[coro->i].ext_hashes) + continue; + + CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", + finders[coro->i].name); + + /* + * Inputs: CHEEVOS_VAR_INFO + * Outputs: CHEEVOS_VAR_GAMEID + */ + CORO_GOSUB(finders[coro->i].label); + + if (coro->gameid != 0) + goto found; + } + + CHEEVOS_LOG("[CHEEVOS]: this game doesn't feature achievements.\n"); + CORO_STOP(); + +found: + +#ifdef CHEEVOS_JSON_OVERRIDE + { + size_t size = 0; + FILE *file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); + + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + + coro->json = (char*)malloc(size + 1); + fread((void*)coro->json, 1, size, file); + + fclose(file); + coro->json[size] = 0; + } +#else + CORO_GOSUB(GET_CHEEVOS); + + if (!coro->json) + { + runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: error loading achievements.\n"); + CORO_STOP(); + } +#endif + +#ifdef CHEEVOS_SAVE_JSON + { + FILE *file = fopen(CHEEVOS_SAVE_JSON, "w"); + fwrite((void*)coro->json, 1, strlen(coro->json), file); + fclose(file); + } +#endif + if (cheevos_parse(coro->json)) + { + if ((void*)coro->json) + free((void*)coro->json); + CORO_STOP(); + } + + if ((void*)coro->json) + free((void*)coro->json); + + if ( cheevos_locals.core.count == 0 + && cheevos_locals.unofficial.count == 0 + && cheevos_locals.lboard_count == 0) + { + runloop_msg_queue_push( + "This game has no achievements.", + 0, 5 * 60, false); + + cheevos_free_cheevo_set(&cheevos_locals.core); + cheevos_free_cheevo_set(&cheevos_locals.unofficial); + + cheevos_locals.core.cheevos = NULL; + cheevos_locals.unofficial.cheevos = NULL; + cheevos_locals.core.count = 0; + cheevos_locals.unofficial.count = 0; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + CORO_STOP(); + } + + cheevos_loaded = true; + + /* + * Inputs: CHEEVOS_VAR_GAMEID + * Outputs: + */ + CORO_GOSUB(DEACTIVATE); + + /* + * Inputs: CHEEVOS_VAR_GAMEID + * Outputs: + */ + CORO_GOSUB(PLAYING); + + if (coro->settings->bools.cheevos_verbose_enable && cheevos_locals.core.count > 0) + { + char msg[256]; + int mode = CHEEVOS_ACTIVE_SOFTCORE; + const cheevo_t* cheevo = cheevos_locals.core.cheevos; + const cheevo_t* end = cheevo + cheevos_locals.core.count; + int number_of_unlocked = cheevos_locals.core.count; + + if (coro->settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + mode = CHEEVOS_ACTIVE_HARDCORE; + + for (; cheevo < end; cheevo++) + if (cheevo->active & mode) + number_of_unlocked--; + + snprintf(msg, sizeof(msg), + "You have %d of %d achievements unlocked.", + number_of_unlocked, cheevos_locals.core.count); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 6 * 60, false); + } + + CORO_GOSUB(GET_BADGES); + CORO_STOP(); + + /************************************************************************** + * Info Tries to identify a SNES game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(SNES_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + + CORO_GOSUB(EVAL_MD5); + + if (coro->count == 0) + { + MD5_Final(coro->hash, &coro->md5); + coro->gameid = 0; + CORO_RET(); + } + + if (coro->count < size_in_megabytes(8)) + { + /* + * Inputs: CHEEVOS_VAR_MD5, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs: CHEEVOS_VAR_MD5 + */ + coro->offset = 0; + coro->count = size_in_megabytes(8) - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a Genesis game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(GENESIS_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + CORO_GOSUB(EVAL_MD5); + + if (coro->count == 0) + { + MD5_Final(coro->hash, &coro->md5); + coro->gameid = 0; + CORO_RET(); + } + + if (coro->count < size_in_megabytes(6)) + { + coro->offset = 0; + coro->count = size_in_megabytes(6) - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify an Atari Lynx game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(LYNX_MD5) + + if (coro->len < 0x0240) + { + coro->gameid = 0; + CORO_RET(); + } + + MD5_Init(&coro->md5); + + coro->offset = 0x0040; + coro->count = 0x0200; + CORO_GOSUB(EVAL_MD5); + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a NES game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(NES_MD5) + + /* Note about the references to the FCEU emulator below. There is no + * core-specific code in this function, it's rather Retro Achievements + * specific code that must be followed to the letter so we compute + * the correct ROM hash. Retro Achievements does indeed use some + * FCEU related method to compute the hash, since its NES emulator + * is based on it. */ + + if (coro->len < sizeof(coro->header)) + { + coro->gameid = 0; + CORO_RET(); + } + + memcpy((void*)&coro->header, coro->data, + sizeof(coro->header)); + + if ( coro->header.id[0] != 'N' + || coro->header.id[1] != 'E' + || coro->header.id[2] != 'S' + || coro->header.id[3] != 0x1a) + { + coro->gameid = 0; + CORO_RET(); + } + + { + size_t romsize = 256; + /* from FCEU core - compute size using the cart mapper */ + int mapper = (coro->header.rom_type >> 4) | (coro->header.rom_type2 & 0xF0); + + if (coro->header.rom_size) + romsize = next_pow2(coro->header.rom_size); + + /* for games not to the power of 2, so we just read enough + * PRG rom from it, but we have to keep ROM_size to the power of 2 + * since PRGCartMapping wants ROM_size to be to the power of 2 + * so instead if not to power of 2, we just use head.ROM_size when + * we use FCEU_read. */ + coro->round = mapper != 53 && mapper != 198 && mapper != 228; + coro->bytes = coro->round ? romsize : coro->header.rom_size; + } + + /* from FCEU core - check if Trainer included in ROM data */ + MD5_Init(&coro->md5); + coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4 + ? sizeof(coro->header) : 0); + coro->count = 0x4000 * coro->bytes; + CORO_GOSUB(EVAL_MD5); + + if (coro->count < 0x4000 * coro->bytes) + { + coro->offset = 0xff; + coro->count = 0x4000 * coro->bytes - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a "generic" game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(GENERIC_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + CORO_GOSUB(EVAL_MD5); + + MD5_Final(coro->hash, &coro->md5); + + if (coro->count == 0) + CORO_RET(); + + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a game based on its filename (with no extension) + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(FILENAME_MD5) + if (!string_is_empty(coro->path)) + { + char base_noext[PATH_MAX_LENGTH]; + fill_pathname_base_noext(base_noext, coro->path, sizeof(base_noext)); + + MD5_Init(&coro->md5); + MD5_Update(&coro->md5, (void*)base_noext, strlen(base_noext)); + MD5_Final(coro->hash, &coro->md5); + + CORO_GOTO(GET_GAMEID); + } + CORO_RET(); + + /************************************************************************** + * Info Evaluates the CHEEVOS_VAR_MD5 hash + * Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT + *************************************************************************/ + CORO_SUB(EVAL_MD5) + + if (coro->count == 0) + coro->count = coro->len; + + if (coro->len - coro->offset < coro->count) + coro->count = coro->len - coro->offset; + + /* size limit */ + if (coro->count > size_in_megabytes(64)) + coro->count = size_in_megabytes(64); + + MD5_Update(&coro->md5, + (void*)((uint8_t*)coro->data + coro->offset), + coro->count); + CORO_RET(); + + /************************************************************************** + * Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value + * Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs CHEEVOS_VAR_MD5 + *************************************************************************/ + CORO_SUB(FILL_MD5) + + { + char buffer[4096]; + + while (coro->count > 0) + { + size_t len = sizeof(buffer); + + if (len > coro->count) + len = coro->count; + + memset((void*)buffer, coro->offset, len); + MD5_Update(&coro->md5, (void*)buffer, len); + coro->count -= len; + } + } + + CORO_RET(); + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs coro->hash + * Outputs CHEEVOS_VAR_GAMEID + *************************************************************************/ + CORO_SUB(GET_GAMEID) + + { + char gameid[16]; + + CHEEVOS_LOG( + "[CHEEVOS]: getting game id for hash %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], + coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], + coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], + coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] + ); + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=gameid&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], + coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], + coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], + coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the game's id: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (!coro->json) + CORO_RET(); + + if (cheevos_get_value(coro->json, + CHEEVOS_JSON_KEY_GAMEID, gameid, sizeof(gameid))) + { + if ((void*)coro->json) + free((void*)coro->json); + CHEEVOS_ERR("[CHEEVOS]: error getting game_id.\n"); + CORO_RET(); + } + + if ((void*)coro->json) + free((void*)coro->json); + CHEEVOS_LOG("[CHEEVOS]: got game id %s.\n", gameid); + coro->gameid = (unsigned)strtol(gameid, NULL, 10); + CORO_RET(); + } + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(GET_CHEEVOS) + + CORO_GOSUB(LOGIN); + + snprintf(coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=patch&g=%u&u=%s&t=%s", + coro->gameid, + coro->settings->arrays.cheevos_username, + cheevos_locals.token); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of cheevos: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (!coro->json) + { + CHEEVOS_ERR("[CHEEVOS]: error getting achievements for game id %u.\n", coro->gameid); + CORO_STOP(); + } + + CHEEVOS_LOG("[CHEEVOS]: got achievements for game id %u.\n", coro->gameid); + CORO_RET(); + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(GET_BADGES) + + badges_ctx = new_badges_ctx; + + { + settings_t *settings = config_get_ptr(); + if (!( + string_is_equal(settings->arrays.menu_driver, "xmb") || + string_is_equal(settings->arrays.menu_driver, "ozone") + ) || + !settings->bools.cheevos_badges_enable) + CORO_RET(); + } + + coro->cheevo = cheevos_locals.core.cheevos; + coro->cheevo_end = cheevos_locals.core.cheevos + cheevos_locals.core.count; + + for (; coro->cheevo < coro->cheevo_end; coro->cheevo++) + { + for (coro->j = 0 ; coro->j < 2; coro->j++) + { + coro->badge_fullpath[0] = '\0'; + fill_pathname_application_special( + coro->badge_fullpath, + sizeof(coro->badge_fullpath), + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES); + + if (!path_is_directory(coro->badge_fullpath)) + path_mkdir(coro->badge_fullpath); + CORO_YIELD(); + if (coro->j == 0) + snprintf(coro->badge_name, + sizeof(coro->badge_name), + "%s.png", coro->cheevo->badge); + else + snprintf(coro->badge_name, + sizeof(coro->badge_name), + "%s_lock.png", coro->cheevo->badge); + + fill_pathname_join( + coro->badge_fullpath, + coro->badge_fullpath, + coro->badge_name, + sizeof(coro->badge_fullpath)); + + if (!badge_exists(coro->badge_fullpath)) + { +#ifdef CHEEVOS_LOG_BADGES + CHEEVOS_LOG( + "[CHEEVOS]: downloading badge %s\n", + coro->badge_fullpath); +#endif + snprintf(coro->url, + sizeof(coro->url), + "http://i.retroachievements.org/Badge/%s", + coro->badge_name); + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!filestream_write_file(coro->badge_fullpath, + coro->json, coro->k)) + CHEEVOS_ERR("[CHEEVOS]: error writing badge %s\n", coro->badge_fullpath); + else + free(coro->json); + } + } + } + } + + CORO_RET(); + + /************************************************************************** + * Info Logs in the user at Retro Achievements + *************************************************************************/ + CORO_SUB(LOGIN) + + if (cheevos_locals.token[0]) + CORO_RET(); + + { + char urle_user[64]; + char urle_login[64]; + const char *username = coro ? coro->settings->arrays.cheevos_username : NULL; + const char *login = NULL; + bool via_token = false; + + if (coro) + { + if (string_is_empty(coro->settings->arrays.cheevos_password)) + { + via_token = true; + login = coro->settings->arrays.cheevos_token; + } + else + login = coro->settings->arrays.cheevos_password; + } + else + login = NULL; + + if (string_is_empty(username) || string_is_empty(login)) + { + runloop_msg_queue_push( + "Missing RetroAchievements account information.", + 0, 5 * 60, false); + runloop_msg_queue_push( + "Please fill in your account information in Settings.", + 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: login info not informed.\n"); + CORO_STOP(); + } + + cheevos_url_encode(username, urle_user, sizeof(urle_user)); + cheevos_url_encode(login, urle_login, sizeof(urle_login)); + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=login&u=%s&%c=%s", + urle_user, via_token ? 't' : 'p', urle_login + ); + + coro->url[sizeof(coro->url) - 1] = 0; + } + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to login: %s\n", + coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + char error_response[64]; + char error_message[256]; + + cheevos_get_value( + coro->json, + CHEEVOS_JSON_KEY_ERROR, + error_response, + sizeof(error_response) + ); + + /* No error, continue with login */ + if (string_is_empty(error_response)) + { + int res = cheevos_get_value( + coro->json, + CHEEVOS_JSON_KEY_TOKEN, + cheevos_locals.token, + sizeof(cheevos_locals.token)); + + if ((void*)coro->json) + free((void*)coro->json); + + if (!res) + { + if (coro->settings->bools.cheevos_verbose_enable) + { + char msg[256]; + snprintf(msg, sizeof(msg), + "RetroAchievements: Logged in as \"%s\".", + coro->settings->arrays.cheevos_username); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 3 * 60, false); + } + + /* Save token to config and clear pass on success */ + *coro->settings->arrays.cheevos_password = '\0'; + strncpy( + coro->settings->arrays.cheevos_token, + cheevos_locals.token, sizeof(cheevos_locals.token) + ); + CORO_RET(); + } + } + + if ((void*)coro->json) + free((void*)coro->json); + + /* Site returned error, display it */ + snprintf(error_message, sizeof(error_message), + "RetroAchievements: %s", + error_response); + error_message[sizeof(error_message) - 1] = 0; + runloop_msg_queue_push(error_message, 0, 5 * 60, false); + *coro->settings->arrays.cheevos_token = '\0'; + + CORO_STOP(); + } + + runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: error getting user token.\n"); + + CORO_STOP(); + + /************************************************************************** + * Info Pauses execution for five seconds + *************************************************************************/ + CORO_SUB(DELAY) + + { + retro_time_t t1; + coro->t0 = cpu_features_get_time_usec(); + + do + { + CORO_YIELD(); + t1 = cpu_features_get_time_usec(); + }while ((t1 - coro->t0) < 3000000); + } + + CORO_RET(); + + /************************************************************************** + * Info Makes a HTTP GET request + * Inputs CHEEVOS_VAR_URL + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(HTTP_GET) + + for (coro->k = 0; coro->k < 5; coro->k++) + { + if (coro->k != 0) + CHEEVOS_LOG("[CHEEVOS]: Retrying HTTP request: %u of 5\n", coro->k + 1); + + coro->json = NULL; + coro->conn = net_http_connection_new( + coro->url, "GET", NULL); + + if (!coro->conn) + { + CORO_GOSUB(DELAY); + continue; + } + + /* Don't bother with timeouts here, it's just a string scan. */ + while (!net_http_connection_iterate(coro->conn)) {} + + /* Error finishing the connection descriptor. */ + if (!net_http_connection_done(coro->conn)) + { + net_http_connection_free(coro->conn); + continue; + } + + coro->http = net_http_new(coro->conn); + + /* Error connecting to the endpoint. */ + if (!coro->http) + { + net_http_connection_free(coro->conn); + CORO_GOSUB(DELAY); + continue; + } + + while (!net_http_update(coro->http, NULL, NULL)) + CORO_YIELD(); + + { + size_t length; + uint8_t *data = net_http_data(coro->http, + &length, false); + + if (data) + { + coro->json = (char*)malloc(length + 1); + + if (coro->json) + { + memcpy((void*)coro->json, (void*)data, length); + free(data); + coro->json[length] = 0; + } + + coro->k = (unsigned)length; + net_http_delete(coro->http); + net_http_connection_free(coro->conn); + CORO_RET(); + } + } + + net_http_delete(coro->http); + net_http_connection_free(coro->conn); + } + + CHEEVOS_LOG("[CHEEVOS]: Couldn't connect to server after 5 tries\n"); + CORO_RET(); + + /************************************************************************** + * Info Deactivates the achievements already awarded + * Inputs CHEEVOS_VAR_GAMEID + * Outputs + *************************************************************************/ + CORO_SUB(DEACTIVATE) + +#ifndef CHEEVOS_DONT_DEACTIVATE + CORO_GOSUB(LOGIN); + + /* Deactivate achievements in softcore mode. */ + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=0", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in softcore: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_SOFTCORE)) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in softcore mode.\n"); + else + CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in softcore mode.\n"); + + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in softcore mode.\n"); + + /* Deactivate achievements in hardcore mode. */ + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=1", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in hardcore: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_HARDCORE)) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in hardcore mode.\n"); + else + CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in hardcore mode.\n"); + + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in hardcore mode.\n"); + +#endif + CORO_RET(); + + /************************************************************************** + * Info Posts the "playing" activity to Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs + *************************************************************************/ + CORO_SUB(PLAYING) + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to post the 'playing' activity: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error posting playing activity.\n"); + + CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); + CORO_RET(); + + CORO_LEAVE(); +} + +static void cheevos_task_handler(retro_task_t *task) +{ + coro_t *coro = (coro_t*)task->state; + + if (!coro) + return; + + if (!cheevos_iterate(coro) || task_get_cancelled(task)) + { + task_set_finished(task, true); + + CHEEVOS_LOCK(cheevos_locals.task_lock); + cheevos_locals.task = NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + if (task_get_cancelled(task)) + { + CHEEVOS_LOG("[CHEEVOS]: Load task cancelled\n"); + } + else + { + CHEEVOS_LOG("[CHEEVOS]: Load task finished\n"); + } + + if (coro->data) + free(coro->data); + + if ((void*)coro->path) + free((void*)coro->path); + + free((void*)coro); + } +} + +bool cheevos_load(const void *data) +{ + retro_task_t *task; + const struct retro_game_info *info = NULL; + coro_t *coro = NULL; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + + if (!cheevos_locals.core_supports || !data) + return false; + + coro = (coro_t*)calloc(1, sizeof(*coro)); + + if (!coro) + return false; + + task = (retro_task_t*)calloc(1, sizeof(*task)); + + if (!task) + { + if ((void*)coro) + free((void*)coro); + return false; + } + + CORO_SETUP(); + + info = (const struct retro_game_info*)data; + + if (info->data) + { + coro->len = info->size; + + /* size limit */ + if (coro->len > size_in_megabytes(64)) + coro->len = size_in_megabytes(64); + + coro->data = malloc(coro->len); + + if (!coro->data) + { + if ((void*)task) + free((void*)task); + if ((void*)coro) + free((void*)coro); + return false; + } + + memcpy(coro->data, info->data, coro->len); + coro->path = NULL; + } + else + { + coro->data = NULL; + coro->path = strdup(info->path); + } + + task->handler = cheevos_task_handler; + task->state = (void*)coro; + task->mute = true; + task->callback = NULL; + task->user_data = NULL; + task->progress = 0; + task->title = NULL; + +#ifdef HAVE_THREADS + if (cheevos_locals.task_lock == NULL) + { + cheevos_locals.task_lock = slock_new(); + } +#endif + + CHEEVOS_LOCK(cheevos_locals.task_lock); + cheevos_locals.task = task; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + task_queue_push(task); + + return true; +} diff --git a/config.def.h b/config.def.h index f0ee60d58b..618fba6174 100644 --- a/config.def.h +++ b/config.def.h @@ -117,8 +117,8 @@ static const unsigned monitor_index = 0; /* Window */ /* Window size. A value of 0 uses window scale * multiplied by the core framebuffer size. */ -static const unsigned window_x = 0; -static const unsigned window_y = 0; +static const unsigned window_width = 1280; +static const unsigned window_height = 720; /* Fullscreen resolution. A value of 0 uses the desktop * resolution. */ diff --git a/configuration.c b/configuration.c index 299f475e99..947011d30f 100644 --- a/configuration.c +++ b/configuration.c @@ -1514,6 +1514,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("video_msg_bgcolor_enable", &settings->bools.video_msg_bgcolor_enable, true, message_bgcolor_enable, false); SETTING_BOOL("video_window_show_decorations", &settings->bools.video_window_show_decorations, true, window_decorations, false); + SETTING_BOOL("video_window_save_positions", &settings->bools.video_window_save_positions, true, false, false); SETTING_BOOL("sustained_performance_mode", &settings->bools.sustained_performance_mode, true, sustained_performance_mode, false); @@ -1589,8 +1590,6 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("video_monitor_index", &settings->uints.video_monitor_index, true, monitor_index, false); SETTING_UINT("video_fullscreen_x", &settings->uints.video_fullscreen_x, true, fullscreen_x, false); SETTING_UINT("video_fullscreen_y", &settings->uints.video_fullscreen_y, true, fullscreen_y, false); - SETTING_UINT("video_window_x", &settings->uints.video_window_x, true, fullscreen_x, false); - SETTING_UINT("video_window_y", &settings->uints.video_window_y, true, fullscreen_y, false); SETTING_UINT("video_window_opacity", &settings->uints.video_window_opacity, true, window_opacity, false); #ifdef HAVE_COMMAND SETTING_UINT("network_cmd_port", &settings->uints.network_cmd_port, true, network_cmd_port, false); @@ -1672,6 +1671,10 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("video_stream_quality", &settings->uints.video_stream_quality, true, RECORD_CONFIG_TYPE_STREAMING_LOW_QUALITY, false); SETTING_UINT("video_record_scale_factor", &settings->uints.video_record_scale_factor, true, 1, false); SETTING_UINT("video_stream_scale_factor", &settings->uints.video_stream_scale_factor, true, 1, false); + SETTING_UINT("video_windowed_position_x", &settings->uints.window_position_x, true, 0, false); + SETTING_UINT("video_windowed_position_y", &settings->uints.window_position_y, true, 0, false); + SETTING_UINT("video_windowed_position_width", &settings->uints.window_position_width, true, window_width, false); + SETTING_UINT("video_windowed_position_height", &settings->uints.window_position_height, true, window_height, false); *size = count; diff --git a/configuration.h b/configuration.h index 5ca67844fb..7555118d62 100644 --- a/configuration.h +++ b/configuration.h @@ -293,6 +293,7 @@ typedef struct settings bool automatically_add_content_to_playlist; bool video_window_show_decorations; + bool video_window_save_positions; bool sustained_performance_mode; } bools; @@ -372,8 +373,6 @@ typedef struct settings unsigned network_cmd_port; unsigned network_remote_base_port; unsigned keymapper_port; - unsigned video_window_x; - unsigned video_window_y; unsigned video_window_opacity; unsigned crt_switch_resolution; unsigned crt_switch_resolution_super; @@ -439,6 +438,11 @@ typedef struct settings unsigned midi_volume; unsigned streaming_mode; + + unsigned window_position_x; + unsigned window_position_y; + unsigned window_position_width; + unsigned window_position_height; } uints; struct diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index f63c819d21..ddce3cc9c0 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -565,6 +565,9 @@ static bool device_is_xperia_play(const char *name) strstr(name, "R800at") || strstr(name, "R800i") || strstr(name, "R800a") || + strstr(name, "R800") || + strstr(name, "Xperia Play") || + strstr(name, "Play") || strstr(name, "SO-01D") ) return true; diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index b580a1bcb0..f9314ada30 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -200,6 +200,8 @@ static bool g_win32_quit = false; static int g_win32_pos_x = CW_USEDEFAULT; static int g_win32_pos_y = CW_USEDEFAULT; +static unsigned g_win32_pos_width = 0; +static unsigned g_win32_pos_height = 0; unsigned g_win32_resize_width = 0; unsigned g_win32_resize_height = 0; @@ -617,6 +619,48 @@ static LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, } #endif +static void win32_set_position_from_config(void) +{ + settings_t *settings = config_get_ptr(); + if (!settings->bools.video_window_save_positions) + return; + + g_win32_pos_x = settings->uints.window_position_x; + g_win32_pos_y = settings->uints.window_position_y; + g_win32_pos_width = settings->uints.window_position_width; + g_win32_pos_height= settings->uints.window_position_height; +} + +static void win32_save_position(void) +{ + RECT rect; + WINDOWPLACEMENT placement; + settings_t *settings = config_get_ptr(); + memset(&placement, 0, sizeof(placement)); + placement.length = sizeof(placement); + + GetWindowPlacement(main_window.hwnd, &placement); + + g_win32_pos_x = placement.rcNormalPosition.left; + g_win32_pos_y = placement.rcNormalPosition.top; + + if (GetWindowRect(main_window.hwnd, &rect)) + { + g_win32_pos_width = rect.right - rect.left; + g_win32_pos_height = rect.bottom - rect.top; + } + if (settings && settings->bools.video_window_save_positions) + { + if (!settings->bools.video_fullscreen && !retroarch_is_forced_fullscreen()) + { + settings->uints.window_position_x = g_win32_pos_x; + settings->uints.window_position_y = g_win32_pos_y; + settings->uints.window_position_width = g_win32_pos_width; + settings->uints.window_position_height = g_win32_pos_height; + } + } +} + static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { @@ -634,6 +678,7 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, *quit = true; break; } + win32_save_position(); break; case WM_DROPFILES: { @@ -649,21 +694,16 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, *quit = true; return win32_handle_keyboard_event(hwnd, message, wparam, lparam); + case WM_MOVE: + win32_save_position(); + break; case WM_CLOSE: case WM_DESTROY: case WM_QUIT: - { - WINDOWPLACEMENT placement; - memset(&placement, 0, sizeof(placement)); - placement.length = sizeof(placement); + win32_save_position(); - GetWindowPlacement(main_window.hwnd, &placement); - - g_win32_pos_x = placement.rcNormalPosition.left; - g_win32_pos_y = placement.rcNormalPosition.top; - g_win32_quit = true; - *quit = true; - } + g_win32_quit = true; + *quit = true; break; case WM_SIZE: /* Do not send resize message if we minimize. */ @@ -678,6 +718,7 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, g_win32_resized = true; } } + win32_save_position(); *quit = true; break; case WM_COMMAND: @@ -719,6 +760,7 @@ LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, case WM_CLOSE: case WM_DESTROY: case WM_QUIT: + case WM_MOVE: case WM_SIZE: case WM_COMMAND: ret = WndProcCommon(&quit, hwnd, message, wparam, lparam); @@ -779,6 +821,7 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, case WM_CLOSE: case WM_DESTROY: case WM_QUIT: + case WM_MOVE: case WM_SIZE: case WM_COMMAND: ret = WndProcCommon(&quit, @@ -878,6 +921,7 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, case WM_CLOSE: case WM_DESTROY: case WM_QUIT: + case WM_MOVE: case WM_SIZE: case WM_COMMAND: ret = WndProcCommon(&quit, hwnd, message, wparam, lparam); @@ -918,12 +962,23 @@ bool win32_window_create(void *data, unsigned style, #endif settings_t *settings = config_get_ptr(); #ifndef _XBOX + unsigned user_width = width; + unsigned user_height = height; + win32_set_position_from_config(); + + if (settings->bools.video_window_save_positions + && !fullscreen) + { + user_width = g_win32_pos_width; + user_height= g_win32_pos_height; + } main_window.hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style, fullscreen ? mon_rect->left : g_win32_pos_x, fullscreen ? mon_rect->top : g_win32_pos_y, - width, height, + user_width, + user_height, NULL, NULL, NULL, data); if (!main_window.hwnd) return false; @@ -1139,9 +1194,10 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, RECT *rect, RECT *mon_rect, DWORD *style) { #if !defined(_XBOX) + bool position_set_from_config = false; + settings_t *settings = config_get_ptr(); if (fullscreen) { - settings_t *settings = config_get_ptr(); /* Windows only reports the refresh rates for modelines as * an integer, so video_refresh_rate needs to be rounded. Also, account * for black frame insertion using video_refresh_rate set to half @@ -1176,8 +1232,23 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, AdjustWindowRect(rect, *style, FALSE); - g_win32_resize_width = *width = rect->right - rect->left; - g_win32_resize_height = *height = rect->bottom - rect->top; + if (settings->bools.video_window_save_positions) + { + win32_set_position_from_config(); + if (g_win32_pos_width != 0 && g_win32_pos_height != 0) + position_set_from_config = true; + } + + if (position_set_from_config) + { + g_win32_resize_width = *width = g_win32_pos_width; + g_win32_resize_height = *height = g_win32_pos_height; + } + else + { + g_win32_resize_width = *width = rect->right - rect->left; + g_win32_resize_height = *height = rect->bottom - rect->top; + } } #endif } @@ -1256,6 +1327,7 @@ bool win32_set_video_mode(void *data, &mon_rect, width, height, fullscreen)) return false; + win32_set_window(&width, &height, fullscreen, windowed_full, &rect); @@ -1353,15 +1425,13 @@ void win32_get_video_output_prev( unsigned curr_width = 0; unsigned curr_height = 0; - memset(&dm, 0, sizeof(dm)); + if (win32_get_video_output(&dm, -1, sizeof(dm))) + { + curr_width = dm.dmPelsWidth; + curr_height = dm.dmPelsHeight; + } - dm.dmSize = sizeof(dm); - - win32_get_video_output_size(&curr_width, &curr_height); - - for (i = 0; - EnumDisplaySettings(NULL, i, &dm) != 0; - i++) + for (i = 0; win32_get_video_output(&dm, i, sizeof(dm)); i++) { if ( dm.dmPelsWidth == curr_width && dm.dmPelsHeight == curr_height) @@ -1458,14 +1528,13 @@ void win32_get_video_output_next( unsigned curr_width = 0; unsigned curr_height = 0; - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); + if (win32_get_video_output(&dm, -1, sizeof(dm))) + { + curr_width = dm.dmPelsWidth; + curr_height = dm.dmPelsHeight; + } - win32_get_video_output_size(&curr_width, &curr_height); - - for (i = 0; - EnumDisplaySettings(NULL, i, &dm) != 0; - i++) + for (i = 0; win32_get_video_output(&dm, i, sizeof(dm)); i++) { if (found) { @@ -1480,13 +1549,23 @@ void win32_get_video_output_next( } } +bool win32_get_video_output(DEVMODE *dm, int mode, size_t len) +{ + memset(dm, 0, len); + dm->dmSize = len; + + if (EnumDisplaySettings(NULL, + (mode == -1) ? ENUM_CURRENT_SETTINGS : mode, dm) == 0) + return false; + + return true; +} + void win32_get_video_output_size(unsigned *width, unsigned *height) { DEVMODE dm; - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) + if (win32_get_video_output(&dm, -1, sizeof(dm))) { *width = dm.dmPelsWidth; *height = dm.dmPelsHeight; diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 04eeeef936..6f899ad491 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -101,6 +101,8 @@ void win32_check_window(bool *quit, void win32_set_window(unsigned *width, unsigned *height, bool fullscreen, bool windowed_full, void *rect_data); +bool win32_get_video_output(DEVMODE *dm, int mode, size_t len); + void win32_get_video_output_size( unsigned *width, unsigned *height); diff --git a/gfx/display_servers/dispserv_null.c b/gfx/display_servers/dispserv_null.c index 22b326cbda..8e17292762 100644 --- a/gfx/display_servers/dispserv_null.c +++ b/gfx/display_servers/dispserv_null.c @@ -48,9 +48,10 @@ const video_display_server_t dispserv_null = { null_display_server_destroy, null_display_server_set_window_opacity, null_display_server_set_window_progress, - NULL, - NULL, - NULL, + NULL, /* set_window_decorations */ + NULL, /* set_resolution */ + NULL, /* get_resolution_list */ + NULL, /* get_output_options */ "null" }; diff --git a/gfx/display_servers/dispserv_win32.c b/gfx/display_servers/dispserv_win32.c index 54c3a79d02..6563441bd5 100644 --- a/gfx/display_servers/dispserv_win32.c +++ b/gfx/display_servers/dispserv_win32.c @@ -107,7 +107,7 @@ static void win32_display_server_destroy(void *data) dispserv_win32_t *dispserv = (dispserv_win32_t*)data; if (win32_orig_width > 0 && win32_orig_height > 0) - video_display_server_switch_resolution(win32_orig_width, win32_orig_height, + video_display_server_set_resolution(win32_orig_width, win32_orig_height, win32_orig_refresh, (float)win32_orig_refresh, crt_center ); #ifdef HAS_TASKBAR_EXT @@ -204,20 +204,16 @@ static bool win32_display_server_set_window_decorations(void *data, bool on) static bool win32_display_server_set_resolution(void *data, unsigned width, unsigned height, int int_hz, float hz, int center) { - LONG res; DEVMODE curDevmode; - DEVMODE devmode; - int iModeNum; int freq = int_hz; - DWORD flags = 0; int depth = 0; dispserv_win32_t *serv = (dispserv_win32_t*)data; if (!serv) return false; - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &curDevmode); + win32_get_video_output(&curDevmode, -1, sizeof(curDevmode)); if (win32_orig_width == 0) win32_orig_width = GetSystemMetrics(SM_CXSCREEN); @@ -239,7 +235,10 @@ static bool win32_display_server_set_resolution(void *data, for (iModeNum = 0;; iModeNum++) { - if (!EnumDisplaySettings(NULL, iModeNum, &devmode)) + LONG res; + DEVMODE devmode; + + if (!win32_get_video_output(&devmode, iModeNum, sizeof(devmode))) break; if (devmode.dmPelsWidth != width) @@ -262,15 +261,15 @@ static bool win32_display_server_set_resolution(void *data, switch (res) { case DISP_CHANGE_SUCCESSFUL: - res = win32_change_display_settings(NULL, &devmode, flags); + res = win32_change_display_settings(NULL, &devmode, 0); switch (res) { - case DISP_CHANGE_SUCCESSFUL: - return true; - case DISP_CHANGE_NOTUPDATED: - return true; - default: - break; + case DISP_CHANGE_SUCCESSFUL: + return true; + case DISP_CHANGE_NOTUPDATED: + return true; + default: + break; } break; case DISP_CHANGE_RESTART: @@ -283,6 +282,62 @@ static bool win32_display_server_set_resolution(void *data, return true; } +void *win32_display_server_get_resolution_list(void *data, + unsigned *len) +{ + DEVMODE dm; + unsigned i, count = 0; + unsigned curr_width = 0; + unsigned curr_height = 0; + unsigned curr_bpp = 0; + unsigned curr_refreshrate = 0; + struct video_display_config *conf = NULL; + + for (i = 0;; i++) + { + if (!win32_get_video_output(&dm, i, sizeof(dm))) + break; + + count++; + } + + if (win32_get_video_output(&dm, -1, sizeof(dm))) + { + curr_width = dm.dmPelsWidth; + curr_height = dm.dmPelsHeight; + curr_bpp = dm.dmBitsPerPel; + curr_refreshrate = dm.dmDisplayFrequency; + } + + *len = count; + conf = (struct video_display_config*)calloc(*len, sizeof(struct video_display_config)); + + if (!conf) + return NULL; + + for (i = 0;; i++) + { + if (!win32_get_video_output(&dm, i, sizeof(dm))) + break; + + conf[i].width = dm.dmPelsWidth; + conf[i].height = dm.dmPelsHeight; + conf[i].bpp = dm.dmBitsPerPel; + conf[i].refreshrate = dm.dmDisplayFrequency; + conf[i].idx = i; + conf[i].current = false; + + if ( (conf[i].width == curr_width) + && (conf[i].height == curr_height) + && (conf[i].refreshrate == curr_refreshrate) + && (conf[i].bpp == curr_bpp) + ) + conf[i].current = true; + } + + return conf; +} + const video_display_server_t dispserv_win32 = { win32_display_server_init, win32_display_server_destroy, @@ -290,6 +345,7 @@ const video_display_server_t dispserv_win32 = { win32_display_server_set_window_progress, win32_display_server_set_window_decorations, win32_display_server_set_resolution, + win32_display_server_get_resolution_list, NULL, /* get_output_options */ "win32" }; diff --git a/gfx/display_servers/dispserv_x11.c b/gfx/display_servers/dispserv_x11.c index f4f6f16f7a..29a13fec55 100644 --- a/gfx/display_servers/dispserv_x11.c +++ b/gfx/display_servers/dispserv_x11.c @@ -29,7 +29,7 @@ static char old_mode[250] = {0}; static char new_mode[250] = {0}; static char xrandr[250] = {0}; static char fbset[150] = {0}; -static char output[250] = {0}; +static char output[500] = {0}; static bool crt_en = false; typedef struct @@ -55,23 +55,28 @@ static void x11_display_server_destroy(void *data) if (crt_en) { - sprintf(output, "xrandr -s %dx%d", orig_width, orig_height); + snprintf(output, sizeof(output), + "xrandr -s %dx%d", orig_width, orig_height); system(output); for (i = 0; i < 3; i++) { - sprintf(output, "xrandr --delmode %s%d %s", "VGA", i, old_mode); + snprintf(output, sizeof(output), + "xrandr --delmode %s%d %s", "VGA", i, old_mode); system(output); - sprintf(output, "xrandr --delmode %s-%d %s", "VGA", i, old_mode); + snprintf(output, sizeof(output), + "xrandr --delmode %s-%d %s", "VGA", i, old_mode); system(output); - sprintf(output, "xrandr --delmode %s%d %s", "DVI", i, old_mode); + snprintf(output, sizeof(output), + "xrandr --delmode %s%d %s", "DVI", i, old_mode); system(output); - sprintf(output, "xrandr --delmode %s-%d %s", "DVI", i, old_mode); + snprintf(output, sizeof(output), + "xrandr --delmode %s-%d %s", "DVI", i, old_mode); system(output); } - sprintf(output, "xrandr --rmmode %s", old_mode); + snprintf(output, sizeof(output), "xrandr --rmmode %s", old_mode); system(output); } @@ -92,7 +97,8 @@ static bool x11_display_server_set_window_opacity(void *data, unsigned opacity) if (opacity == (unsigned)-1) XDeleteProperty(g_x11_dpy, g_x11_win, net_wm_opacity); else - XChangeProperty(g_x11_dpy, g_x11_win, net_wm_opacity, cardinal, 32, PropModeReplace, (const unsigned char*)&opacity, 1); + XChangeProperty(g_x11_dpy, g_x11_win, net_wm_opacity, cardinal, + 32, PropModeReplace, (const unsigned char*)&opacity, 1); return true; } @@ -101,9 +107,11 @@ static bool x11_display_server_set_window_decorations(void *data, bool on) { dispserv_x11_t *serv = (dispserv_x11_t*)data; - serv->decorations = on; + if (serv) + serv->decorations = on; - /* menu_setting performs a reinit instead to properly apply decoration changes */ + /* menu_setting performs a reinit instead to properly apply + * decoration changes */ return true; } @@ -131,7 +139,7 @@ static bool x11_display_server_set_resolution(void *data, /* set core refresh from hz */ video_monitor_set_refresh_rate(hz); - /* following code is the mode line genorator */ + /* following code is the mode line generator */ hsp = width * 1.140; hfp = width * 1.055; @@ -144,9 +152,7 @@ static bool x11_display_server_set_resolution(void *data, roundw = roundf((float)pwidth / (float)height * 100) / 100; if (height > width) - { roundw = roundf((float)height / (float)width * 100) / 100; - } if (roundw > 1.35) roundw = 1.25; @@ -158,111 +164,88 @@ static bool x11_display_server_set_resolution(void *data, hmax = hbp; if (height < 241) - { vmax = 261; - } if (height < 241 && hz > 56 && hz < 58) - { vmax = 280; - } if (height < 241 && hz < 55) - { vmax = 313; - } if (height > 250 && height < 260 && hz > 54) - { vmax = 296; - } if (height > 250 && height < 260 && hz > 52 && hz < 54) - { vmax = 285; - } if (height > 250 && height < 260 && hz < 52) - { vmax = 313; - } if (height > 260 && height < 300) - { vmax = 318; - } if (height > 400 && hz > 56) - { vmax = 533; - } if (height > 520 && hz < 57) - { vmax = 580; - } if (height > 300 && hz < 56) - { vmax = 615; - } if (height > 500 && hz < 56) - { vmax = 624; - } if (height > 300) - { pdefault = pdefault * 2; - } vfp = height + ((vmax - height) / 2) - pdefault; if (height < 300) - { - vsp = vfp + 3; /* needs to me 3 for progressive */ - } + vsp = vfp + 3; /* needs to be 3 for progressive */ if (height > 300) - { - vsp = vfp + 6; /* needs to me 6 for interlaced */ - } + vsp = vfp + 6; /* needs to be 6 for interlaced */ vbp = vmax; if (height < 300) - { pixel_clock = (hmax * vmax * hz) / 1000000; - } if (height > 300) - { pixel_clock = ((hmax * vmax * hz) / 1000000) / 2; - } - /* above code is the modeline genorator */ + /* above code is the modeline generator */ /* create interlaced newmode from modline variables */ if (height < 300) { - snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); + snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, + width, hfp, hsp, hbp, height, vfp, vsp, vbp); system(xrandr); } /* create interlaced newmode from modline variables */ if (height > 300) { - snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d interlace -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); + snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d interlace -hsync -vsync", width, height, hz, pixel_clock, + width, hfp, hsp, hbp, height, vfp, vsp, vbp); system(xrandr); } /* variable for new mode */ snprintf(new_mode, sizeof(new_mode), "%dx%d_%0.2f", width, height, hz); - /* need to run loops for DVI0 - DVI-2 and VGA0 - VGA-2 outputs to add and delete modes */ + /* need to run loops for DVI0 - DVI-2 and VGA0 - VGA-2 outputs to + * add and delete modes */ for (i = 0; i < 3; i++) { - snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "DVI", i, new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "DVI", i, + new_mode); system(output); - snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "DVI", i, old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "DVI", i, + old_mode); system(output); } + for (i = 0; i < 3; i++) { - snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "DVI", i, new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "DVI", i, + new_mode); system(output); - snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "DVI", i, old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "DVI", i, + old_mode); system(output); } + for (i = 0; i < 3; i++) { snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "VGA", i, new_mode); @@ -270,6 +253,7 @@ static bool x11_display_server_set_resolution(void *data, snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "VGA", i, old_mode); system(output); } + for (i = 0; i < 3; i++) { snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "VGA", i, new_mode); @@ -285,18 +269,20 @@ static bool x11_display_server_set_resolution(void *data, snprintf(output, sizeof(output), "xrandr --rmmode %s", old_mode); system(output); - system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recapture window. */ + /* needs xdotool installed. needed to recapture window. */ + system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* variable for old mode */ snprintf(old_mode, sizeof(old_mode), "%s", new_mode); - system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recapture window. */ + /* needs xdotool installed. needed to recapture window. */ + system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* Second run needed as some times it runs to fast to capture first time */ return true; } -const char *x11_display_server_get_output_options(void) +const char *x11_display_server_get_output_options(void *data) { /* TODO/FIXME - hardcoded for now; list should be built up dynamically later */ return "HDMI-0|HDMI-1|HDMI-2|HDMI-3|DVI-0|DVI-1|DVI-2|DVI-3|VGA-0|VGA-1|VGA-2|VGA-3|Config"; @@ -306,9 +292,10 @@ const video_display_server_t dispserv_x11 = { x11_display_server_init, x11_display_server_destroy, x11_display_server_set_window_opacity, - NULL, + NULL, /* set_window_progress */ x11_display_server_set_window_decorations, x11_display_server_set_resolution, + NULL, /* get_resolution_list */ x11_display_server_get_output_options, "x11" }; diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 480cb20c03..aaaf22e36c 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -51,7 +51,7 @@ #include "../../input/input_driver.h" #include "../../input/input_keymaps.h" -// Generated from xdg-shell.xml +/* Generated from xdg-shell.xml */ #include "../common/wayland/xdg-shell.h" @@ -350,7 +350,7 @@ static const struct wl_pointer_listener pointer_listener = { pointer_handle_axis, }; -// TODO: implement check for resize +/* TODO: implement check for resize */ static void touch_handle_down(void *data, struct wl_touch *wl_touch, @@ -574,14 +574,12 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, { gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - // TODO: implement resizing + /* TODO: implement resizing */ wl->configured = false; } -// TODO: implement xdg_toplevel close - - +/* TODO: implement xdg_toplevel close */ static const struct xdg_toplevel_listener xdg_toplevel_listener = { handle_toplevel_config, }; @@ -1310,14 +1308,14 @@ static bool gfx_ctx_wl_set_video_mode(void *data, xdg_toplevel_set_app_id (wl->xdg_toplevel, "RetroArch"); xdg_toplevel_set_title (wl->xdg_toplevel, "RetroArch"); - // Waiting for xdg_toplevel to be configured before starting to draw + /* Waiting for xdg_toplevel to be configured before starting to draw */ wl_surface_commit(wl->surface); wl->configured = true; while (wl->configured) wl_display_dispatch(wl->input.dpy); - // Waiting for the "initial" set of globals to appear + /* Waiting for the "initial" set of globals to appear */ wl_display_roundtrip(wl->input.dpy); xdg_wm_base_add_listener(wl->shell, &xdg_shell_listener, NULL); diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 784cf41c7f..f9bed812e8 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -480,11 +480,11 @@ error: return false; } -static void gl_glsl_strip_parameter_pragmas(char *source) +static void gl_glsl_strip_parameter_pragmas(char *source, const char *str) { /* #pragma parameter lines tend to have " characters in them, * which is not legal GLSL. */ - char *s = strstr(source, "#pragma parameter"); + char *s = strstr(source, str); while (s) { @@ -492,7 +492,7 @@ static void gl_glsl_strip_parameter_pragmas(char *source) * so we can just replace the entire line with spaces. */ while (*s != '\0' && *s != '\n') *s++ = ' '; - s = strstr(s, "#pragma parameter"); + s = strstr(s, str); } } @@ -506,7 +506,7 @@ static bool gl_glsl_load_source_path(struct video_shader_pass *pass, if (nitems <= 0 || len <= 0) return false; - gl_glsl_strip_parameter_pragmas(pass->source.string.vertex); + gl_glsl_strip_parameter_pragmas(pass->source.string.vertex, "#pragma parameter"); pass->source.string.fragment = strdup(pass->source.string.vertex); return pass->source.string.fragment && pass->source.string.vertex; } diff --git a/gfx/video_crt_switch.c b/gfx/video_crt_switch.c index 282d2aea39..d154cfa41b 100644 --- a/gfx/video_crt_switch.c +++ b/gfx/video_crt_switch.c @@ -88,7 +88,7 @@ static void switch_res_crt(unsigned width, unsigned height) { if (height > 100) { - video_display_server_switch_resolution(width, height, + video_display_server_set_resolution(width, height, ra_set_core_hz, ra_core_hz, crt_center_adjust); video_driver_apply_state_changes(); } diff --git a/gfx/video_display_server.c b/gfx/video_display_server.c index 98fd57eca1..0f77f6697a 100644 --- a/gfx/video_display_server.c +++ b/gfx/video_display_server.c @@ -90,14 +90,21 @@ bool video_display_server_set_window_decorations(bool on) } -bool video_display_server_switch_resolution(unsigned width, unsigned height, +bool video_display_server_set_resolution(unsigned width, unsigned height, int int_hz, float hz, int center) { - if (current_display_server && current_display_server->switch_resolution) - return current_display_server->switch_resolution(current_display_server_data, width, height, int_hz, hz, center); + if (current_display_server && current_display_server->set_resolution) + return current_display_server->set_resolution(current_display_server_data, width, height, int_hz, hz, center); return false; } +void *video_display_server_get_resolution_list(unsigned *size) +{ + if (current_display_server && current_display_server->get_resolution_list) + return current_display_server->get_resolution_list(current_display_server_data, size); + return NULL; +} + const char *video_display_server_get_output_options(void) { if (current_display_server && current_display_server->get_output_options) diff --git a/gfx/video_display_server.h b/gfx/video_display_server.h index 9a39100807..2824b4b4ee 100644 --- a/gfx/video_display_server.h +++ b/gfx/video_display_server.h @@ -23,6 +23,16 @@ RETRO_BEGIN_DECLS +typedef struct video_display_config +{ + unsigned width; + unsigned height; + unsigned bpp; + unsigned refreshrate; + unsigned idx; + bool current; +} video_display_config_t; + typedef struct video_display_server { void *(*init)(void); @@ -30,8 +40,10 @@ typedef struct video_display_server bool (*set_window_opacity)(void *data, unsigned opacity); bool (*set_window_progress)(void *data, int progress, bool finished); bool (*set_window_decorations)(void *data, bool on); - bool (*switch_resolution)(void *data, unsigned width, + bool (*set_resolution)(void *data, unsigned width, unsigned height, int int_hz, float hz, int center); + void *(*get_resolution_list)(void *data, + unsigned *size); const char *(*get_output_options)(void *data); const char *ident; } video_display_server_t; @@ -46,10 +58,12 @@ bool video_display_server_set_window_progress(int progress, bool finished); bool video_display_server_set_window_decorations(bool on); -bool video_display_server_switch_resolution( +bool video_display_server_set_resolution( unsigned width, unsigned height, int int_hz, float hz, int center); +void *video_display_server_get_resolution_list(unsigned *size); + const char *video_display_server_get_output_options(void); const char *video_display_server_get_ident(void); diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 75f2f46bfb..c3157f8c6c 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -985,24 +985,16 @@ static bool video_driver_init_internal(bool *video_is_threaded) } else { - if (settings->uints.video_window_x || settings->uints.video_window_y) + if (settings->bools.video_force_aspect) { - width = settings->uints.video_window_x; - height = settings->uints.video_window_y; + /* Do rounding here to simplify integer scale correctness. */ + unsigned base_width = + roundf(geom->base_height * video_driver_get_aspect_ratio()); + width = roundf(base_width * settings->floats.video_scale); } else - { - if (settings->bools.video_force_aspect) - { - /* Do rounding here to simplify integer scale correctness. */ - unsigned base_width = - roundf(geom->base_height * video_driver_get_aspect_ratio()); - width = roundf(base_width * settings->floats.video_scale); - } - else - width = roundf(geom->base_width * settings->floats.video_scale); - height = roundf(geom->base_height * settings->floats.video_scale); - } + width = roundf(geom->base_width * settings->floats.video_scale); + height = roundf(geom->base_height * settings->floats.video_scale); } if (width && height) @@ -1491,15 +1483,6 @@ void video_driver_menu_settings(void **list_data, void *list_info_data, (void)subgroup_info; (void)global; -#if defined(GEKKO) || defined(__CELLOS_LV2__) - CONFIG_ACTION( - list, list_info, - MENU_ENUM_LABEL_SCREEN_RESOLUTION, - MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - group_info, - subgroup_info, - parent_group); -#endif #if defined(__CELLOS_LV2__) CONFIG_BOOL( list, list_info, diff --git a/griffin/griffin.c b/griffin/griffin.c index d2b8b5dedc..d057b0a8f2 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1275,7 +1275,12 @@ MENU #include "../menu/drivers/xmb.c" #endif #ifdef HAVE_OZONE -#include "../menu/drivers/ozone.c" +#include "../menu/drivers/ozone/ozone.c" +#include "../menu/drivers/ozone/ozone_display.c" +#include "../menu/drivers/ozone/ozone_entries.c" +#include "../menu/drivers/ozone/ozone_sidebar.c" +#include "../menu/drivers/ozone/ozone_texture.c" +#include "../menu/drivers/ozone/ozone_theme.c" #endif #ifdef HAVE_STRIPES diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index aa6aa0489c..3e0339e9a0 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -1057,11 +1057,21 @@ static void handle_hotplug(android_input_t *android, * This device is composed of two hid devices * We make it look like one device */ - else if(strstr(device_model, "R800") && - ( - strstr(device_name, "keypad-game-zeus") || - strstr(device_name, "keypad-zeus") - ) + else if( + ( + strstr(device_model, "R800x") || + strstr(device_model, "R800at") || + strstr(device_model, "R800i") || + strstr(device_model, "R800a") || + strstr(device_model, "R800") || + strstr(device_model, "Xperia Play") || + strstr(device_model, "Play") || + strstr(device_model, "SO-01D") + ) && ( + strstr(device_name, "keypad-game-zeus") || + strstr(device_name, "keypad-zeus") || + strstr(device_name, "Android Gamepad") + ) ) { /* only use the hack if the device is one of the built-in devices */ diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index 88b3ade95b..865fd63e2b 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -2669,9 +2669,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, "Specify custom X axis position for onscreen text.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, @@ -3722,3 +3722,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 813689be7c..13f6fbb55a 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -210,7 +210,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "æˆå°±åˆ—表(硬核)" /*FIXME:"Achievement List (Hardcore)"*/ + "æˆå°±åˆ—表(硬核模å¼ï¼‰" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -650,9 +650,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, "èœå•é¡¹æ­£å¸¸é¢œè‰²") MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "å‡") + "å¦") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "最大è¿è¡Œé€Ÿåº¦") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "收è—夹") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, "显示帧率") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, @@ -1707,7 +1709,7 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, "èœå•æ ‡é¢˜é¢œè‰²") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, - "真") + "是") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, "UI Companion Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, @@ -4613,7 +4615,7 @@ MSG_HASH( "Output Display ID") MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_RECORDING, - "Start Recording" + "开始录制" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_START_RECORDING, @@ -4621,7 +4623,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_RECORDING, - "Stop Recording" + "åœæ­¢å½•åˆ¶" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_STOP_RECORDING, @@ -4676,11 +4678,11 @@ MSG_HASH( "YouTube" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_TWITCH_STREAM_KEY, - "Twitch Stream Key") + "Twitch 直播密钥") MSG_HASH(MENU_ENUM_LABEL_VALUE_YOUTUBE_STREAM_KEY, - "YouTube Stream Key") + "YouTube 直播密钥") MSG_HASH(MENU_ENUM_LABEL_VALUE_STREAMING_MODE, - "Streaming Mode") + "直播模å¼") MSG_HASH(MENU_ENUM_LABEL_VALUE_STREAMING_TITLE, "直播标题") MSG_HASH( @@ -4700,46 +4702,52 @@ MSG_HASH( "OK" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, - "èœå•é¢œè‰²ä¸»é¢˜") + "èœå•ä¸»é¢˜é¢œè‰²") MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, - "Basic White" + "白色" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, - "Basic Black" + "黑色" ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, - "Select a different color theme." + "选择ä¸åŒçš„主题颜色。" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, "Use preferred system color theme") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, "Use your operating system's color theme (if any) - overrides theme settings.") MSG_HASH(MSG_RESAMPLER_QUALITY_LOWEST, - "Lowest") + "最低") MSG_HASH(MSG_RESAMPLER_QUALITY_LOWER, - "Lower") + "较低") MSG_HASH(MSG_RESAMPLER_QUALITY_NORMAL, - "Normal") + "一般") MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHER, - "Higher") + "较高") MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHEST, - "Highest") + "最高") MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE, - "No music available." + "没有音ä¹ã€‚" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_VIDEOS_AVAILABLE, - "No videos available." + "没有视频。" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_IMAGES_AVAILABLE, - "No images available." + "没有图片。" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, - "No favorites available." + "没有收è—。" ) +MSG_HASH( + MSG_MISSING_ASSETS, + "Warning: Missing assets, use the Online Updater if available" + ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index c025ffed0a..ad767dcb25 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -2499,9 +2499,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, "Specify custom X axis position for onscreen text.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, @@ -3500,3 +3500,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index f87411aa60..3a6c051535 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -3636,3 +3636,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_el.h b/intl/msg_hash_el.h index e3bc73e9e9..3954649d49 100644 --- a/intl/msg_hash_el.h +++ b/intl/msg_hash_el.h @@ -4862,11 +4862,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution." + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution" + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, @@ -7730,3 +7730,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index c28eff54ef..b4eda865a4 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -2372,9 +2372,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, "Specify custom X axis position for onscreen text.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, @@ -3375,3 +3375,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index acbef69d97..d60e909750 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -1,3 +1,29 @@ +#ifdef HAVE_LAKKA_SWITCH +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SWITCH_GPU_PROFILE, + "GPU Overclock" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_GPU_PROFILE, + "Acelera el procesador de video" + ) + MSG_HASH( + MENU_ENUM_LABEL_VALUE_SWITCH_BACKLIGHT_CONTROL, + "Brillo de pantalla" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_BACKLIGHT_CONTROL, + "Ajusta el brillo de la pantalla" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SWITCH_CPU_PROFILE, + "CPU Overclock" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_CPU_PROFILE, + "Acelera el procesador" + ) +#endif MSG_HASH( MSG_COMPILER, "Compilador" @@ -8,7 +34,7 @@ MSG_HASH( ) MSG_HASH( MSG_NATIVE, - "Native") + "Nativo") MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, "Dispositivo desconectado del puerto" @@ -1489,6 +1515,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LANG_ARABIC, "Ãrabe" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_GREEK, + "Griego" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, "Analógico izquierdo" @@ -2880,6 +2910,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, "Mostrar fecha y hora" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, + "Estilo de fecha y hora" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, + "Cambia la forma en que se muestra la fecha y hora" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TITLE_COLOR, "Color de títulos del menú" @@ -4930,6 +4968,19 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, "Auto-aplicar los trucos después que el juego cargue" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_REPEAT_COUNT, + "La cantidad de veces que el truco será aplicado.\n" + "Usar junto a las otras dos optionces de iteración para afectar regiones grandes de memoria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_ADDRESS, + "Después de cada 'Número de iteraciones' la dirección de memoria será incrementada este número multiplicado por 'Tamaño de búsqueda de memoria'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_VALUE, + "Después de cada 'Número de iteraciones' el Valor será incrementado esta cantidad" + ) MSG_HASH( MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, "Rebobinar un determinado número de frames a la vez, para aumentar la velocidad del rebobinado" @@ -6378,7 +6429,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, - "" + "" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, @@ -6837,6 +6888,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, "Duración (ms) de la vibración secundaria" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_COUNT, + "Número de iteraciones" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_VALUE, + "Incrementar Valor cada iteración" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_ADDRESS, + "Incrementar Dirección cada iteración" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, "Agregar nuevo truco después de este" @@ -7607,15 +7670,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SPLIT_JOYCON, - "Split Joy-Con" + "Joy-Con separados" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_TO_DEFAULT_CONFIG, - "Reset To Defaults" + "Restablecer configuraciones" ) MSG_HASH( MENU_ENUM_SUBLABEL_RESET_TO_DEFAULT_CONFIG, - "Reset the current configuration to default values." + "Cambia la configuración acutal a los valores por defecto" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_OK, @@ -7627,43 +7690,63 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, - "Basic White" + "Blanco Básico" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, - "Basic Black" + "Negro Básico" ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, - "Select a different color theme." + "Seleccione un color diferente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Usar los colores del sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Preferir los colores del sistema operativo si están disponibles" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWEST, + "Muy Baja" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWER, + "Baja" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_NORMAL, + "Normal" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHER, + "Alta" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHEST, + "Ultra" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use preferred system color theme") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use your operating system's color theme (if any) - overrides theme settings.") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWEST, - "Lowest") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWER, - "Lower") -MSG_HASH(MSG_RESAMPLER_QUALITY_NORMAL, - "Normal") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHER, - "Higher") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHEST, - "Highest") MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE, - "No music available." + "No hay música disponibles" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_VIDEOS_AVAILABLE, - "No videos available." + "No hay videos disponibles" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_IMAGES_AVAILABLE, - "No images available." + "No hay imágenes disponibles" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, - "No favorites available." + "No hay favoritos disponibles" ) +MSG_HASH( + MSG_MISSING_ASSETS, + "ADVERTENCIA: Faltan recursos, use el Actualizador si está disponible" + ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 2d9a560a34..0d2de27a1b 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -3534,3 +3534,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index fe7be6d34a..053e67d894 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -3594,3 +3594,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "Nessun preferito disponibile." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 813efe054a..e0619ed04d 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -4043,3 +4043,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 60b669cbfb..1a16c5793d 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -3495,3 +3495,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 9ac9cf2db7..1571d7e991 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -259,6 +259,8 @@ MSG_HASH(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST, "deferred_dropdown_box_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL, "deferred_dropdown_box_list_special") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION, + "deferred_dropdown_box_list_resolution") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_CONFIGURATIONS_LIST, "deferred_configurations_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST, @@ -1565,6 +1567,8 @@ MSG_HASH(MENU_ENUM_LABEL_INPUT_DRIVER_LINUXRAW, "linuxraw") MSG_HASH(MENU_ENUM_LABEL_VIDEO_WINDOW_SHOW_DECORATIONS, "video_window_show_decorations") +MSG_HASH(MENU_ENUM_LABEL_VIDEO_WINDOW_SAVE_POSITION, + "video_window_save_position") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_BORDER_FILLER_ENABLE, "menu_rgui_border_filler_enable") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index b32f6d954e..e1ffd5b701 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -2388,9 +2388,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, "Specify custom X axis position for onscreen text.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, @@ -3381,3 +3381,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "Geen favorieten beschikbaar." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 882a39f1bc..e510a17a18 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -3797,3 +3797,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "Brak ulubionych." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index f576b77216..c63c4404f9 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -261,7 +261,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Configurações" + "Arquivo de Configuração" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TAB, @@ -2910,45 +2910,45 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, "Exibir data e hora" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, "Estilo da data / hora" ) - MSG_HASH( - MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, - "Altera o estilo da data atual ou como a hora é mostrada dentro do menu." +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, + "Altera o estilo da data atual ou como a hora é mostrada dentro do menu." ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HMS, - "YYYY-MM-DD HH:MM:SS" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HMS, + "YYYY-MM-DD HH:MM:SS" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HM, - "YYYY-MM-DD HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HM, + "YYYY-MM-DD HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MDYYYY, - "MM-DD-YYYY HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MDYYYY, + "MM-DD-YYYY HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HMS, - "HH:MM:SS" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HMS, + "HH:MM:SS" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HM, - "HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HM, + "HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_DM_HM, - "DD/MM HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_DM_HM, + "DD/MM HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MD_HM, - "MM/DD HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MD_HM, + "MM/DD HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_AM_PM, - "HH:MM:SS (AM/PM)" + MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_AM_PM, + "HH:MM:SS (AM/PM)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TITLE_COLOR, @@ -5002,7 +5002,8 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_REPEAT_COUNT, - "O número de vezes que a trapaça será aplicada. Use com as outras duas opções de iteração para afetar grandes áreas da memória." + "O número de vezes que a trapaça será aplicada.\n" + "Use com as outras duas opções de iteração para afetar grandes áreas da memória." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_ADDRESS, @@ -6052,11 +6053,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, - "Exibir Configurações" + "Exibir Arquivo de Configuração" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, - "Exibir/ocultar a opção 'Configurações'." + "Exibir/ocultar a opção 'Arquivo de Configuração'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, @@ -7721,43 +7722,63 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, - "Basic White" + "Branco Básico" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, - "Basic Black" + "Preto Básico" ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, - "Select a different color theme." + "Selecione um tema de cor diferente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Use a cor preferida do tema do sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Usar a cor do tema do seu sistema operacional (se houver) - substitui as configurações do tema." + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWEST, + "Muito baixa" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWER, + "Baixa" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_NORMAL, + "Normal" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHER, + "Alta" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHEST, + "Muito alta" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use preferred system color theme") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use your operating system's color theme (if any) - overrides theme settings.") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWEST, - "Lowest") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWER, - "Lower") -MSG_HASH(MSG_RESAMPLER_QUALITY_NORMAL, - "Normal") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHER, - "Higher") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHEST, - "Highest") MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE, - "No music available." + "Nenhuma música disponível." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_VIDEOS_AVAILABLE, - "No videos available." + "Nenhum vídeo disponível." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_IMAGES_AVAILABLE, - "No images available." + "Nenhuma imagem disponível." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, - "No favorites available." + "Não há favoritos disponíveis." ) +MSG_HASH( + MSG_MISSING_ASSETS, + "Aviso: Recursos ausentes, use o Atualizador Online se disponível" + ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index 056b071dca..6aa36f56d5 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -3461,3 +3461,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 51bb95d1de..51d2ef1e6f 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -3664,3 +3664,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index e4d584270c..f400919e98 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2910,45 +2910,45 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, "Show date / time" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, - "Style of date / time" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, + "Style of date / time" ) - MSG_HASH( - MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, - "Changes the style current date and/or time is shown inside the menu." +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, + "Changes the style current date and/or time is shown inside the menu." ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HMS, - "YYYY-MM-DD HH:MM:SS" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HMS, + "YYYY-MM-DD HH:MM:SS" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HM, - "YYYY-MM-DD HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_YMD_HM, + "YYYY-MM-DD HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MDYYYY, - "MM-DD-YYYY HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MDYYYY, + "MM-DD-YYYY HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HMS, - "HH:MM:SS" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HMS, + "HH:MM:SS" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HM, - "HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_HM, + "HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_DM_HM, - "DD/MM HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_DM_HM, + "DD/MM HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MD_HM, - "MM/DD HH:MM" +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_MD_HM, + "MM/DD HH:MM" ) - MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_AM_PM, - "HH:MM:SS (AM/PM)" + MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE_AM_PM, + "HH:MM:SS (AM/PM)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TITLE_COLOR, @@ -4886,19 +4886,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, - "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible." + "Set the custom width for the display window." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, - "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible." + "Set the custom height for the display window." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SAVE_POSITION, + "Remember window size and position, enabling this has precedence over Windowed Scale" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution." + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution" + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, @@ -4995,19 +4999,20 @@ MSG_HASH( MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, "Apply cheat immediately after toggling." -) + ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, "Auto-apply cheats when game loads." -) + ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_REPEAT_COUNT, - "The number of times the cheat will be applied. Use with the other two Iteration options to affect large areas of memory." + "The number of times the cheat will be applied.\n" + "Use with the other two Iteration options to affect large areas of memory." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_ADDRESS, "After each 'Number of Iterations' the Memory Address will be increased by this number times the 'Memory Search Size'." -) + ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_VALUE, "After each 'Number of Iterations' the Value will be increased by this amount." @@ -6922,15 +6927,15 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_COUNT, "Number of Iterations" -) + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_VALUE, "Value Increase Each Iteration" -) + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_ADDRESS, "Address Increase Each Iteration" -) + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, "Add New Cheat After This One" @@ -7731,20 +7736,34 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, "Select a different color theme." ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use preferred system color theme") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, - "Use your operating system's color theme (if any) - overrides theme settings.") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWEST, - "Lowest") -MSG_HASH(MSG_RESAMPLER_QUALITY_LOWER, - "Lower") -MSG_HASH(MSG_RESAMPLER_QUALITY_NORMAL, - "Normal") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHER, - "Higher") -MSG_HASH(MSG_RESAMPLER_QUALITY_HIGHEST, - "Highest") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Use preferred system color theme" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Use your operating system's color theme (if any) - overrides theme settings." + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWEST, + "Lowest" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_LOWER, + "Lower" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_NORMAL, + "Normal" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHER, + "Higher" + ) +MSG_HASH( + MSG_RESAMPLER_QUALITY_HIGHEST, + "Highest" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE, "No music available." @@ -7761,3 +7780,9 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH( + MSG_MISSING_ASSETS, + "Warning: Missing assets, use the Online Updater if available" + ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Positions") diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index 56937789be..e1c45a5d7e 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -2537,9 +2537,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") + "Set the custom width size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") + "Set the custom height size for the non-windowed fullscreen mode. Leaving it unset will use the desktop resolution.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, "Specify custom X axis position for onscreen text.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, @@ -3534,3 +3534,5 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, "No favorites available." ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + "Remember Window Position and Size") diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 6748c44dad..4e1a9785ba 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -128,7 +128,8 @@ extern "C" { /* LIGHTGUN device is similar to Guncon-2 for PlayStation 2. * It reports X/Y coordinates in screen space (similar to the pointer) - * in the range [-0x8000, 0x7fff] in both axes, with zero being center. + * in the range [-0x8000, 0x7fff] in both axes, with zero being center and + * -0x8000 being out of bounds. * As well as reporting on/off screen state. It features a trigger, * start/select buttons, auxiliary action buttons and a * directional pad. A forced off-screen shot can be requested for @@ -139,7 +140,8 @@ extern "C" { /* The ANALOG device is an extension to JOYPAD (RetroPad). * Similar to DualShock2 it adds two analog sticks and all buttons can * be analog. This is treated as a separate device type as it returns - * axis values in the full analog range of [-0x8000, 0x7fff]. + * axis values in the full analog range of [-0x7fff, 0x7fff], + * although some devices may return -0x8000. * Positive X axis is right. Positive Y axis is down. * Buttons are returned in the range [0, 0x7fff]. * Only use ANALOG type when polling for analog values. diff --git a/menu/cbs/menu_cbs_deferred_push.c b/menu/cbs/menu_cbs_deferred_push.c index 39fd92b9ff..7f8d37d4cc 100644 --- a/menu/cbs/menu_cbs_deferred_push.c +++ b/menu/cbs/menu_cbs_deferred_push.c @@ -613,6 +613,7 @@ generic_deferred_push_clear_general(deferred_image_history_list, PUSH_DEFAULT, D generic_deferred_push_clear_general(deferred_video_history_list, PUSH_DEFAULT, DISPLAYLIST_VIDEO_HISTORY) generic_deferred_push_clear_general(deferred_push_dropdown_box_list, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST) generic_deferred_push_clear_general(deferred_push_dropdown_box_list_special, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_SPECIAL) +generic_deferred_push_clear_general(deferred_push_dropdown_box_list_resolution, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_RESOLUTION) static int menu_cbs_init_bind_deferred_push_compare_label( menu_file_list_cbs_t *cbs, @@ -633,6 +634,11 @@ static int menu_cbs_init_bind_deferred_push_compare_label( BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_dropdown_box_list_special); return 0; } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_dropdown_box_list_resolution); + return 0; + } else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_browse_url_list); diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 577e7d993e..a4d9230bce 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -60,6 +60,7 @@ #include "../../verbosity.h" #include "../../lakka.h" #include "../../wifi/wifi_driver.h" +#include "../../gfx/video_display_server.h" #include @@ -150,6 +151,8 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl) return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST; case ACTION_OK_DL_DROPDOWN_BOX_LIST_SPECIAL: return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL; + case ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION: + return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION; case ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST: return MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST; case ACTION_OK_DL_ACCOUNTS_LIST: @@ -323,6 +326,15 @@ int generic_action_ok_displaylist_push(const char *path, info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL; dl_type = DISPLAYLIST_GENERIC; break; + case ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION: + info.type = type; + info.directory_ptr = idx; + info_path = path; + info_label = msg_hash_to_str( + MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION); + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION; + dl_type = DISPLAYLIST_GENERIC; + break; case ACTION_OK_DL_USER_BINDS_LIST: info.type = type; info.directory_ptr = idx; @@ -4449,6 +4461,45 @@ static int action_ok_push_dropdown_item(const char *path, return 0; } +static int action_ok_push_dropdown_item_resolution(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + char str[100]; + char *pch = NULL; + unsigned width = 0; + unsigned height = 0; + unsigned refreshrate = 0; + + snprintf(str, sizeof(str), "%s", path); + + pch = strtok(str, "x"); + if (pch) + width = strtoul(pch, NULL, 0); + pch = strtok(NULL, " "); + if (pch) + height = strtoul(pch, NULL, 0); + pch = strtok(NULL, "("); + if (pch) + refreshrate = strtoul(pch, NULL, 0); + + if (video_display_server_set_resolution(width, height, + refreshrate, (float)refreshrate, 0)) + { + settings_t *settings = config_get_ptr(); + + video_monitor_set_refresh_rate((float)refreshrate); + + settings->uints.video_fullscreen_x = width; + settings->uints.video_fullscreen_y = height; + + /* TODO/FIXME - menu drivers like XMB don't rescale + * automatically */ + return menu_cbs_exit(); + } + + return 0; +} + static int action_ok_push_default(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -4587,6 +4638,7 @@ default_action_ok_help(action_ok_help_load_content, MENU_ENUM_LABEL_HELP_LOADING static int action_ok_video_resolution(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { +#if defined(__CELLOS_LV2__) || defined(GEKKO) unsigned width = 0; unsigned height = 0; @@ -4610,6 +4662,12 @@ static int action_ok_video_resolution(const char *path, width, height); runloop_msg_queue_push(msg, 1, 100, true); } +#else + generic_action_ok_displaylist_push( + NULL, + NULL, NULL, 0, 0, 0, + ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION); +#endif return 0; } @@ -5555,6 +5613,9 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_DROPDOWN_ITEM: BIND_ACTION_OK(cbs, action_ok_push_dropdown_item); break; + case MENU_SETTING_DROPDOWN_ITEM_RESOLUTION: + BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_resolution); + break; case MENU_SETTING_ACTION_CORE_DISK_OPTIONS: BIND_ACTION_OK(cbs, action_ok_push_default); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index c4ff5f6cf5..34c9259106 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -194,6 +194,7 @@ default_sublabel_macro(action_bind_sublabel_video_window_width, MENU_ default_sublabel_macro(action_bind_sublabel_video_window_height, MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT) default_sublabel_macro(action_bind_sublabel_video_fullscreen_x, MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X) default_sublabel_macro(action_bind_sublabel_video_fullscreen_y, MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y) +default_sublabel_macro(action_bind_sublabel_video_save_window_position, MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SAVE_POSITION) default_sublabel_macro(action_bind_sublabel_video_message_pos_x, MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X) default_sublabel_macro(action_bind_sublabel_video_message_pos_y, MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y) default_sublabel_macro(action_bind_sublabel_video_font_size, MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE) @@ -1624,6 +1625,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_FULLSCREEN_Y: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_fullscreen_y); break; + case MENU_ENUM_LABEL_VIDEO_WINDOW_SAVE_POSITION: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_save_window_position); + break; case MENU_ENUM_LABEL_QUIT_RETROARCH: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quit_retroarch); break; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index de5b97afa9..b3dc2440b8 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -1251,6 +1251,12 @@ int menu_cbs_init_bind_title(menu_file_list_cbs_t *cbs, BIND_ACTION_GET_TITLE(cbs, action_get_title_dropdown_item); return 0; } + if (string_is_equal(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_title_dropdown_item); + return 0; + } if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS))) { BIND_ACTION_GET_TITLE(cbs, action_get_quick_menu_views_settings_list); diff --git a/menu/drivers/nuklear/nk_common.c b/menu/drivers/nuklear/nk_common.c index 67323c0cf1..61800585fd 100644 --- a/menu/drivers/nuklear/nk_common.c +++ b/menu/drivers/nuklear/nk_common.c @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2014-2017 - Jean-Andr� Santoni - * Copyright (C) 2016-2017 - Andr�s Su�rez + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Andrés Suárez * * RetroArch 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 Found- diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c deleted file mode 100644 index ac4acce042..0000000000 --- a/menu/drivers/ozone.c +++ /dev/null @@ -1,4500 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2014-2017 - Jean-André Santoni - * Copyright (C) 2016-2017 - Brad Parker - * Copyright (C) 2018 - Alfredo Monclús - * Copyright (C) 2018 - natinusala - * - * RetroArch 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 Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch 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 RetroArch. - * If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "menu_generic.h" - -#include "../menu_driver.h" -#include "../menu_animation.h" -#include "../menu_input.h" - -#include "../widgets/menu_input_dialog.h" -#include "../widgets/menu_osk.h" - -#include "../../configuration.h" -#include "../../cheevos/badges.h" -#include "../../content.h" -#include "../../core_info.h" -#include "../../core.h" -#include "../../retroarch.h" -#include "../../verbosity.h" -#include "../../tasks/tasks_internal.h" - -#define FONT_SIZE_FOOTER 18 -#define FONT_SIZE_TITLE 36 -#define FONT_SIZE_TIME 22 -#define FONT_SIZE_ENTRIES_LABEL 24 -#define FONT_SIZE_ENTRIES_SUBLABEL 18 -#define FONT_SIZE_SIDEBAR 24 - -#define ANIMATION_PUSH_ENTRY_DURATION 10 -#define ANIMATION_CURSOR_DURATION 8 -#define ANIMATION_CURSOR_PULSE 30 - -#define ENTRIES_START_Y 127 - -#define INTERVAL_BATTERY_LEVEL_CHECK (30 * 1000000) -#define INTERVAL_OSK_CURSOR (0.5f * 1000000) - -static float ozone_pure_white[16] = { - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, -}; - -static float ozone_backdrop[16] = { - 0.00, 0.00, 0.00, 0.75, - 0.00, 0.00, 0.00, 0.75, - 0.00, 0.00, 0.00, 0.75, - 0.00, 0.00, 0.00, 0.75, -}; - -static float ozone_osk_backdrop[16] = { - 0.00, 0.00, 0.00, 0.15, - 0.00, 0.00, 0.00, 0.15, - 0.00, 0.00, 0.00, 0.15, - 0.00, 0.00, 0.00, 0.15, -}; - -enum OZONE_TEXTURE { - OZONE_TEXTURE_RETROARCH = 0, - OZONE_TEXTURE_CURSOR_BORDER, - - OZONE_TEXTURE_LAST -}; - -static char *OZONE_TEXTURES_FILES[OZONE_TEXTURE_LAST] = { - "retroarch", - "cursor_border" -}; - -enum OZONE_THEME_TEXTURES { - OZONE_THEME_TEXTURE_BUTTON_A = 0, - OZONE_THEME_TEXTURE_BUTTON_B, - OZONE_THEME_TEXTURE_SWITCH, - OZONE_THEME_TEXTURE_CHECK, - - OZONE_THEME_TEXTURE_CURSOR_NO_BORDER, - OZONE_THEME_TEXTURE_CURSOR_STATIC, - - OZONE_THEME_TEXTURE_LAST -}; - -static char *OZONE_THEME_TEXTURES_FILES[OZONE_THEME_TEXTURE_LAST] = { - "button_a", - "button_b", - "switch", - "check", - "cursor_noborder", - "cursor_static" -}; - -enum OZONE_TAB_TEXTURES { - OZONE_TAB_TEXTURE_MAIN_MENU = 0, - OZONE_TAB_TEXTURE_SETTINGS, - OZONE_TAB_TEXTURE_HISTORY, - OZONE_TAB_TEXTURE_FAVORITES, - OZONE_TAB_TEXTURE_MUSIC, - OZONE_TAB_TEXTURE_VIDEO, - OZONE_TAB_TEXTURE_IMAGE, - OZONE_TAB_TEXTURE_NETWORK, - OZONE_TAB_TEXTURE_SCAN_CONTENT, - - OZONE_TAB_TEXTURE_LAST -}; - -static char *OZONE_TAB_TEXTURES_FILES[OZONE_TAB_TEXTURE_LAST] = { - "retroarch", - "settings", - "history", - "favorites", - "music", - "video", - "image", - "netplay", - "add" -}; - -enum -{ - OZONE_SYSTEM_TAB_MAIN = 0, - OZONE_SYSTEM_TAB_SETTINGS, - OZONE_SYSTEM_TAB_HISTORY, - OZONE_SYSTEM_TAB_FAVORITES, - OZONE_SYSTEM_TAB_MUSIC, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - OZONE_SYSTEM_TAB_VIDEO, -#endif -#ifdef HAVE_IMAGEVIEWER - OZONE_SYSTEM_TAB_IMAGES, -#endif -#ifdef HAVE_NETWORKING - OZONE_SYSTEM_TAB_NETPLAY, -#endif - OZONE_SYSTEM_TAB_ADD, - - /* End of this enum - use the last one to determine num of possible tabs */ - OZONE_SYSTEM_TAB_LAST -}; - -static enum msg_hash_enums ozone_system_tabs_value[OZONE_SYSTEM_TAB_LAST] = { - MENU_ENUM_LABEL_VALUE_MAIN_MENU, - MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, - MENU_ENUM_LABEL_VALUE_MUSIC_TAB, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - MENU_ENUM_LABEL_VALUE_VIDEO_TAB, -#endif -#ifdef HAVE_IMAGEVIEWER - MENU_ENUM_LABEL_VALUE_IMAGES_TAB, -#endif -#ifdef HAVE_NETWORKING - MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, -#endif - MENU_ENUM_LABEL_VALUE_ADD_TAB -}; - -static enum menu_settings_type ozone_system_tabs_type[OZONE_SYSTEM_TAB_LAST] = { - MENU_SETTINGS, - MENU_SETTINGS_TAB, - MENU_HISTORY_TAB, - MENU_FAVORITES_TAB, - MENU_MUSIC_TAB, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - MENU_VIDEO_TAB, -#endif -#ifdef HAVE_IMAGEVIEWER - MENU_IMAGES_TAB, -#endif -#ifdef HAVE_NETWORKING - MENU_NETPLAY_TAB, -#endif - MENU_ADD_TAB -}; - -static enum msg_hash_enums ozone_system_tabs_idx[OZONE_SYSTEM_TAB_LAST] = { - MENU_ENUM_LABEL_MAIN_MENU, - MENU_ENUM_LABEL_SETTINGS_TAB, - MENU_ENUM_LABEL_HISTORY_TAB, - MENU_ENUM_LABEL_FAVORITES_TAB, - MENU_ENUM_LABEL_MUSIC_TAB, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - MENU_ENUM_LABEL_VIDEO_TAB, -#endif -#ifdef HAVE_IMAGEVIEWER - MENU_ENUM_LABEL_IMAGES_TAB, -#endif -#ifdef HAVE_NETWORKING - MENU_ENUM_LABEL_NETPLAY_TAB, -#endif - MENU_ENUM_LABEL_ADD_TAB -}; - -static unsigned ozone_system_tabs_icons[OZONE_SYSTEM_TAB_LAST] = { - OZONE_TAB_TEXTURE_MAIN_MENU, - OZONE_TAB_TEXTURE_SETTINGS, - OZONE_TAB_TEXTURE_HISTORY, - OZONE_TAB_TEXTURE_FAVORITES, - OZONE_TAB_TEXTURE_MUSIC, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - OZONE_TAB_TEXTURE_VIDEO, -#endif -#ifdef HAVE_IMAGEVIEWER - OZONE_TAB_TEXTURE_IMAGE, -#endif -#ifdef HAVE_NETWORKING - OZONE_TAB_TEXTURE_NETWORK, -#endif - OZONE_TAB_TEXTURE_SCAN_CONTENT -}; - -enum -{ - OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU = 0, - OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS, - OZONE_ENTRIES_ICONS_TEXTURE_HISTORY, - OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES, - OZONE_ENTRIES_ICONS_TEXTURE_MUSICS, -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - OZONE_ENTRIES_ICONS_TEXTURE_MOVIES, -#endif -#ifdef HAVE_NETWORKING - OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY, - OZONE_ENTRIES_ICONS_TEXTURE_ROOM, - OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN, - OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY, -#endif -#ifdef HAVE_IMAGEVIEWER - OZONE_ENTRIES_ICONS_TEXTURE_IMAGES, -#endif - OZONE_ENTRIES_ICONS_TEXTURE_SETTING, - OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING, - OZONE_ENTRIES_ICONS_TEXTURE_ARROW, - OZONE_ENTRIES_ICONS_TEXTURE_RUN, - OZONE_ENTRIES_ICONS_TEXTURE_CLOSE, - OZONE_ENTRIES_ICONS_TEXTURE_RESUME, - OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE, - OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE, - OZONE_ENTRIES_ICONS_TEXTURE_UNDO, - OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO, - OZONE_ENTRIES_ICONS_TEXTURE_WIFI, - OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS, - OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS, - OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS, - OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS, - OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST, - OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT, - OZONE_ENTRIES_ICONS_TEXTURE_RELOAD, - OZONE_ENTRIES_ICONS_TEXTURE_RENAME, - OZONE_ENTRIES_ICONS_TEXTURE_FILE, - OZONE_ENTRIES_ICONS_TEXTURE_FOLDER, - OZONE_ENTRIES_ICONS_TEXTURE_ZIP, - OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE, - OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE, - OZONE_ENTRIES_ICONS_TEXTURE_MUSIC, - OZONE_ENTRIES_ICONS_TEXTURE_IMAGE, - OZONE_ENTRIES_ICONS_TEXTURE_MOVIE, - OZONE_ENTRIES_ICONS_TEXTURE_CORE, - OZONE_ENTRIES_ICONS_TEXTURE_RDB, - OZONE_ENTRIES_ICONS_TEXTURE_CURSOR, - OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON, - OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF, - OZONE_ENTRIES_ICONS_TEXTURE_CLOCK, - OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL, - OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING, - OZONE_ENTRIES_ICONS_TEXTURE_POINTER, - OZONE_ENTRIES_ICONS_TEXTURE_ADD, - OZONE_ENTRIES_ICONS_TEXTURE_KEY, - OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER, - OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE, - OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS, - OZONE_ENTRIES_ICONS_TEXTURE_AUDIO, - OZONE_ENTRIES_ICONS_TEXTURE_EXIT, - OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP, - OZONE_ENTRIES_ICONS_TEXTURE_INFO, - OZONE_ENTRIES_ICONS_TEXTURE_HELP, - OZONE_ENTRIES_ICONS_TEXTURE_NETWORK, - OZONE_ENTRIES_ICONS_TEXTURE_POWER, - OZONE_ENTRIES_ICONS_TEXTURE_SAVING, - OZONE_ENTRIES_ICONS_TEXTURE_UPDATER, - OZONE_ENTRIES_ICONS_TEXTURE_VIDEO, - OZONE_ENTRIES_ICONS_TEXTURE_RECORD, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS, - OZONE_ENTRIES_ICONS_TEXTURE_MIXER, - OZONE_ENTRIES_ICONS_TEXTURE_LOG, - OZONE_ENTRIES_ICONS_TEXTURE_OSD, - OZONE_ENTRIES_ICONS_TEXTURE_UI, - OZONE_ENTRIES_ICONS_TEXTURE_USER, - OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY, - OZONE_ENTRIES_ICONS_TEXTURE_LATENCY, - OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS, - OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST, - OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU, - OZONE_ENTRIES_ICONS_TEXTURE_REWIND, - OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY, - OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE, - OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS, - OZONE_ENTRIES_ICONS_TEXTURE_STREAM, - OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT, - OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT, - OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK, - OZONE_ENTRIES_ICONS_TEXTURE_LAST -}; - -#define HEX_R(hex) ((hex >> 16) & 0xFF) * (1.0f / 255.0f) -#define HEX_G(hex) ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f) -#define HEX_B(hex) ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f) - -#define COLOR_HEX_TO_FLOAT(hex, alpha) { \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha \ -} - -#define COLOR_TEXT_ALPHA(color, alpha) (color & 0xFFFFFF00) | alpha - -static float ozone_sidebar_background_light[16] = { - 0.94, 0.94, 0.94, 1.00, - 0.94, 0.94, 0.94, 1.00, - 0.94, 0.94, 0.94, 1.00, - 0.94, 0.94, 0.94, 1.00, -}; - -static float ozone_sidebar_gradient_top_light[16] = { - 0.94, 0.94, 0.94, 1.00, - 0.94, 0.94, 0.94, 1.00, - 0.922, 0.922, 0.922, 1.00, - 0.922, 0.922, 0.922, 1.00, -}; - -static float ozone_sidebar_gradient_bottom_light[16] = { - 0.922, 0.922, 0.922, 1.00, - 0.922, 0.922, 0.922, 1.00, - 0.94, 0.94, 0.94, 1.00, - 0.94, 0.94, 0.94, 1.00, -}; - -static float ozone_sidebar_background_dark[16] = { - 0.2, 0.2, 0.2, 1.00, - 0.2, 0.2, 0.2, 1.00, - 0.2, 0.2, 0.2, 1.00, - 0.2, 0.2, 0.2, 1.00, -}; - -static float ozone_sidebar_gradient_top_dark[16] = { - 0.2, 0.2, 0.2, 1.00, - 0.2, 0.2, 0.2, 1.00, - 0.18, 0.18, 0.18, 1.00, - 0.18, 0.18, 0.18, 1.00, -}; - -static float ozone_sidebar_gradient_bottom_dark[16] = { - 0.18, 0.18, 0.18, 1.00, - 0.18, 0.18, 0.18, 1.00, - 0.2, 0.2, 0.2, 1.00, - 0.2, 0.2, 0.2, 1.00, -}; - -static float ozone_border_0_light[16] = COLOR_HEX_TO_FLOAT(0x50EFD9, 1.00); -static float ozone_border_1_light[16] = COLOR_HEX_TO_FLOAT(0x0DB6D5, 1.00); - -static float ozone_border_0_dark[16] = COLOR_HEX_TO_FLOAT(0x198AC6, 1.00); -static float ozone_border_1_dark[16] = COLOR_HEX_TO_FLOAT(0x89F1F2, 1.00); - -typedef struct ozone_theme -{ - /* Background color */ - float background[16]; - - /* Float colors for quads and icons */ - float header_footer_separator[16]; - float text[16]; - float selection[16]; - float selection_border[16]; - float entries_border[16]; - float entries_icon[16]; - float text_selected[16]; - float message_background[16]; - - /* RGBA colors for text */ - uint32_t text_rgba; - uint32_t text_selected_rgba; - uint32_t text_sublabel_rgba; - - /* Sidebar color */ - float *sidebar_background; - float *sidebar_top_gradient; - float *sidebar_bottom_gradient; - - /* - Fancy cursor colors - */ - float *cursor_border_0; - float *cursor_border_1; - - menu_texture_item textures[OZONE_THEME_TEXTURE_LAST]; - - const char *name; -} ozone_theme_t; - -ozone_theme_t ozone_theme_light = { - COLOR_HEX_TO_FLOAT(0xEBEBEB, 1.00), - - COLOR_HEX_TO_FLOAT(0x2B2B2B, 1.00), - COLOR_HEX_TO_FLOAT(0x333333, 1.00), - COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), - COLOR_HEX_TO_FLOAT(0x10BEC5, 1.00), - COLOR_HEX_TO_FLOAT(0xCDCDCD, 1.00), - COLOR_HEX_TO_FLOAT(0x333333, 1.00), - COLOR_HEX_TO_FLOAT(0x374CFF, 1.00), - COLOR_HEX_TO_FLOAT(0xF0F0F0, 1.00), - - 0x333333FF, - 0x374CFFFF, - 0x878787FF, - - ozone_sidebar_background_light, - ozone_sidebar_gradient_top_light, - ozone_sidebar_gradient_bottom_light, - - ozone_border_0_light, - ozone_border_1_light, - - {0}, - - "light" -}; - -ozone_theme_t ozone_theme_dark = { - COLOR_HEX_TO_FLOAT(0x2D2D2D, 1.00), - - COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), - COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), - COLOR_HEX_TO_FLOAT(0x212227, 1.00), - COLOR_HEX_TO_FLOAT(0x2DA3CB, 1.00), - COLOR_HEX_TO_FLOAT(0x51514F, 1.00), - COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), - COLOR_HEX_TO_FLOAT(0x00D9AE, 1.00), - COLOR_HEX_TO_FLOAT(0x464646, 1.00), - - 0xFFFFFFFF, - 0x00FFC5FF, - 0x9F9FA1FF, - - ozone_sidebar_background_dark, - ozone_sidebar_gradient_top_dark, - ozone_sidebar_gradient_bottom_dark, - - ozone_border_0_dark, - ozone_border_1_dark, - - {0}, - - "dark" -}; - -ozone_theme_t *ozone_themes[] = { - &ozone_theme_light, - &ozone_theme_dark -}; - -static unsigned ozone_themes_count = sizeof(ozone_themes) / sizeof(ozone_themes[0]); -static unsigned last_color_theme = 0; -static bool last_use_preferred_system_color_theme = false; -static ozone_theme_t *ozone_default_theme = &ozone_theme_light; /* also used as a tag for cursor animation */ - -typedef struct ozone_handle -{ - uint64_t frame_count; - - struct - { - font_data_t *footer; - font_data_t *title; - font_data_t *time; - font_data_t *entries_label; - font_data_t *entries_sublabel; - font_data_t *sidebar; - } fonts; - - struct - { - video_font_raster_block_t footer; - video_font_raster_block_t title; - video_font_raster_block_t time; - video_font_raster_block_t entries_label; - video_font_raster_block_t entries_sublabel; - video_font_raster_block_t sidebar; - } raster_blocks; - - menu_texture_item textures[OZONE_THEME_TEXTURE_LAST]; - menu_texture_item icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LAST]; - menu_texture_item tab_textures[OZONE_TAB_TEXTURE_LAST]; - - char title[PATH_MAX_LENGTH]; - - char assets_path[PATH_MAX_LENGTH]; - char png_path[PATH_MAX_LENGTH]; - char icons_path[PATH_MAX_LENGTH]; - char tab_path[PATH_MAX_LENGTH]; - - uint8_t system_tab_end; - uint8_t tabs[OZONE_SYSTEM_TAB_LAST]; - - size_t categories_selection_ptr; /* active tab id */ - size_t categories_active_idx_old; - - bool cursor_in_sidebar; - bool cursor_in_sidebar_old; - - struct - { - float cursor_alpha; - float scroll_y; - float scroll_y_sidebar; - - float list_alpha; - - float messagebox_alpha; - } animations; - - bool fade_direction; /* false = left to right, true = right to left */ - - size_t selection; /* currently selected entry */ - size_t selection_old; /* previously selected entry (for fancy animation) */ - size_t selection_old_list; - - unsigned entries_height; - - int depth; - - bool draw_sidebar; - float sidebar_offset; - - unsigned title_font_glyph_width; - unsigned entry_font_glyph_width; - unsigned sublabel_font_glyph_width; - - ozone_theme_t *theme; - - struct { - float selection_border[16]; - float selection[16]; - float entries_border[16]; - float entries_icon[16]; - float entries_checkmark[16]; - float cursor_alpha[16]; - - unsigned cursor_state; /* 0 -> 1 -> 0 -> 1 [...] */ - float cursor_border[16]; - float message_background[16]; - } theme_dynamic; - - bool need_compute; - - file_list_t *selection_buf_old; - - bool draw_old_list; - float scroll_old; - - char *pending_message; - bool has_all_assets; - - bool is_playlist; - bool is_playlist_old; - - bool empty_playlist; - - bool osk_cursor; /* true = display it, false = don't */ - bool messagebox_state; - bool messagebox_state_old; - bool should_draw_messagebox; - - unsigned old_list_offset_y; - - file_list_t *horizontal_list; /* console tabs */ -} ozone_handle_t; - -/* If you change this struct, also - change ozone_alloc_node and - ozone_copy_node */ -typedef struct ozone_node -{ - /* Entries */ - unsigned height; - unsigned position_y; - bool wrap; - - /* Console tabs */ - char *console_name; - uintptr_t icon; - uintptr_t content_icon; -} ozone_node_t; - -static const char *ozone_entries_icon_texture_path(ozone_handle_t *ozone, unsigned id) -{ - char icon_fullpath[255]; - char *icon_name = NULL; - -switch (id) - { - case OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU: -#if defined(HAVE_LAKKA) - icon_name = "lakka.png"; - break; -#else - icon_name = "retroarch.png"; - break; -#endif - case OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS: - icon_name = "settings.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_HISTORY: - icon_name = "history.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES: - icon_name = "favorites.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE: - icon_name = "add-favorite.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_MUSICS: - icon_name = "musics.png"; - break; -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - case OZONE_ENTRIES_ICONS_TEXTURE_MOVIES: - icon_name = "movies.png"; - break; -#endif -#ifdef HAVE_IMAGEVIEWER - case OZONE_ENTRIES_ICONS_TEXTURE_IMAGES: - icon_name = "images.png"; - break; -#endif - case OZONE_ENTRIES_ICONS_TEXTURE_SETTING: - icon_name = "setting.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING: - icon_name = "subsetting.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ARROW: - icon_name = "arrow.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RUN: - icon_name = "run.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CLOSE: - icon_name = "close.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RESUME: - icon_name = "resume.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CLOCK: - icon_name = "clock.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL: - icon_name = "battery-full.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING: - icon_name = "battery-charging.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_POINTER: - icon_name = "pointer.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE: - icon_name = "savestate.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE: - icon_name = "loadstate.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_UNDO: - icon_name = "undo.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO: - icon_name = "core-infos.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_WIFI: - icon_name = "wifi.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS: - icon_name = "core-options.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS: - icon_name = "core-input-remapping-options.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS: - icon_name = "core-cheat-options.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS: - icon_name = "core-disk-options.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS: - icon_name = "core-shader-options.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST: - icon_name = "achievement-list.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT: - icon_name = "screenshot.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RELOAD: - icon_name = "reload.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RENAME: - icon_name = "rename.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_FILE: - icon_name = "file.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_FOLDER: - icon_name = "folder.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ZIP: - icon_name = "zip.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_MUSIC: - icon_name = "music.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE: - icon_name = "favorites-content.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_IMAGE: - icon_name = "image.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_MOVIE: - icon_name = "movie.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CORE: - icon_name = "core.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RDB: - icon_name = "database.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CURSOR: - icon_name = "cursor.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON: - icon_name = "on.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF: - icon_name = "off.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ADD: - icon_name = "add.png"; - break; -#ifdef HAVE_NETWORKING - case OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY: - icon_name = "netplay.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ROOM: - icon_name = "menu_room.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN: - icon_name = "menu_room_lan.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY: - icon_name = "menu_room_relay.png"; - break; -#endif - case OZONE_ENTRIES_ICONS_TEXTURE_KEY: - icon_name = "key.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER: - icon_name = "key-hover.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE: - icon_name = "dialog-slice.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS: - icon_name = "menu_achievements.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_AUDIO: - icon_name = "menu_audio.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS: - icon_name = "menu_drivers.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_EXIT: - icon_name = "menu_exit.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP: - icon_name = "menu_frameskip.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_HELP: - icon_name = "menu_help.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INFO: - icon_name = "menu_info.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS: - icon_name = "Libretro - Pad.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_LATENCY: - icon_name = "menu_latency.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_NETWORK: - icon_name = "menu_network.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_POWER: - icon_name = "menu_power.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_RECORD: - icon_name = "menu_record.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SAVING: - icon_name = "menu_saving.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_UPDATER: - icon_name = "menu_updater.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_VIDEO: - icon_name = "menu_video.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_MIXER: - icon_name = "menu_mixer.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_LOG: - icon_name = "menu_log.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_OSD: - icon_name = "menu_osd.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_UI: - icon_name = "menu_ui.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_USER: - icon_name = "menu_user.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY: - icon_name = "menu_privacy.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST: - icon_name = "menu_playlist.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU: - icon_name = "menu_quickmenu.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_REWIND: - icon_name = "menu_rewind.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY: - icon_name = "menu_overlay.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE: - icon_name = "menu_override.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS: - icon_name = "menu_notifications.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_STREAM: - icon_name = "menu_stream.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN: - icon_name = "menu_shutdown.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U: - icon_name = "input_DPAD-U.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D: - icon_name = "input_DPAD-D.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L: - icon_name = "input_DPAD-L.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R: - icon_name = "input_DPAD-R.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U: - icon_name = "input_STCK-U.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D: - icon_name = "input_STCK-D.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L: - icon_name = "input_STCK-L.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R: - icon_name = "input_STCK-R.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P: - icon_name = "input_STCK-P.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U: - icon_name = "input_BTN-U.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D: - icon_name = "input_BTN-D.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L: - icon_name = "input_BTN-L.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R: - icon_name = "input_BTN-R.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB: - icon_name = "input_LB.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB: - icon_name = "input_RB.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT: - icon_name = "input_LT.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT: - icon_name = "input_RT.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT: - icon_name = "input_SELECT.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START: - icon_name = "input_START.png"; - break; - case OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK: - icon_name = "menu_check.png"; - break; - } - - fill_pathname_join( - icon_fullpath, - ozone->icons_path, - icon_name, - sizeof(icon_fullpath) - ); - - if (!filestream_exists(icon_fullpath)) - { - return "subsetting.png"; - } - else - return icon_name; -} - -static unsigned ozone_entries_icon_get_id(ozone_handle_t *ozone, - enum msg_hash_enums enum_idx, unsigned type, bool active) -{ - switch (enum_idx) - { - case MENU_ENUM_LABEL_CORE_OPTIONS: - case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS; - case MENU_ENUM_LABEL_ADD_TO_FAVORITES: - case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: - return OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE; - case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: - return OZONE_ENTRIES_ICONS_TEXTURE_UNDO; - case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS; - case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; - case MENU_ENUM_LABEL_DISK_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS; - case MENU_ENUM_LABEL_SHADER_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; - case MENU_ENUM_LABEL_ACHIEVEMENT_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST; - case MENU_ENUM_LABEL_ACHIEVEMENT_LIST_HARDCORE: - return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST; - case MENU_ENUM_LABEL_SAVE_STATE: - return OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE; - case MENU_ENUM_LABEL_LOAD_STATE: - return OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE; - case MENU_ENUM_LABEL_PARENT_DIRECTORY: - case MENU_ENUM_LABEL_UNDO_LOAD_STATE: - case MENU_ENUM_LABEL_UNDO_SAVE_STATE: - return OZONE_ENTRIES_ICONS_TEXTURE_UNDO; - case MENU_ENUM_LABEL_TAKE_SCREENSHOT: - return OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT; - case MENU_ENUM_LABEL_DELETE_ENTRY: - return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; - case MENU_ENUM_LABEL_RESTART_CONTENT: - return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; - case MENU_ENUM_LABEL_RENAME_ENTRY: - return OZONE_ENTRIES_ICONS_TEXTURE_RENAME; - case MENU_ENUM_LABEL_RESUME_CONTENT: - return OZONE_ENTRIES_ICONS_TEXTURE_RESUME; - case MENU_ENUM_LABEL_FAVORITES: - case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; - case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR: - return OZONE_ENTRIES_ICONS_TEXTURE_RDB; - - - /* Menu collection submenus*/ - case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_ZIP; - case MENU_ENUM_LABEL_GOTO_FAVORITES: - return OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE; - case MENU_ENUM_LABEL_GOTO_IMAGES: - return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; - case MENU_ENUM_LABEL_GOTO_VIDEO: - return OZONE_ENTRIES_ICONS_TEXTURE_MOVIE; - case MENU_ENUM_LABEL_GOTO_MUSIC: - return OZONE_ENTRIES_ICONS_TEXTURE_MUSIC; - - /* Menu icons */ - case MENU_ENUM_LABEL_CONTENT_SETTINGS: - case MENU_ENUM_LABEL_UPDATE_ASSETS: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: - case MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GAME: - return OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU; - case MENU_ENUM_LABEL_START_CORE: - case MENU_ENUM_LABEL_CHEAT_START_OR_CONT: - return OZONE_ENTRIES_ICONS_TEXTURE_RUN; - case MENU_ENUM_LABEL_CORE_LIST: - case MENU_ENUM_LABEL_CORE_SETTINGS: - case MENU_ENUM_LABEL_CORE_UPDATER_LIST: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: - case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE; - case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: - case MENU_ENUM_LABEL_SCAN_FILE: - return OZONE_ENTRIES_ICONS_TEXTURE_FILE; - case MENU_ENUM_LABEL_ONLINE_UPDATER: - case MENU_ENUM_LABEL_UPDATER_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_UPDATER; - case MENU_ENUM_LABEL_UPDATE_LAKKA: - return OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU; - case MENU_ENUM_LABEL_UPDATE_CHEATS: - return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; - case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; - case MENU_ENUM_LABEL_UPDATE_OVERLAYS: - case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY; - case MENU_ENUM_LABEL_UPDATE_CG_SHADERS: - case MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS: - case MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS: - case MENU_ENUM_LABEL_AUTO_SHADERS_ENABLE: - case MENU_ENUM_LABEL_VIDEO_SHADER_PARAMETERS: - return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; - case MENU_ENUM_LABEL_INFORMATION: - case MENU_ENUM_LABEL_INFORMATION_LIST: - case MENU_ENUM_LABEL_SYSTEM_INFORMATION: - case MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES: - return OZONE_ENTRIES_ICONS_TEXTURE_INFO; - case MENU_ENUM_LABEL_UPDATE_DATABASES: - case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_RDB; - case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: - return OZONE_ENTRIES_ICONS_TEXTURE_CURSOR; - case MENU_ENUM_LABEL_HELP_LIST: - case MENU_ENUM_LABEL_HELP_CONTROLS: - case MENU_ENUM_LABEL_HELP_LOADING_CONTENT: - case MENU_ENUM_LABEL_HELP_SCANNING_CONTENT: - case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: - case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: - case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: - return OZONE_ENTRIES_ICONS_TEXTURE_HELP; - case MENU_ENUM_LABEL_QUIT_RETROARCH: - return OZONE_ENTRIES_ICONS_TEXTURE_EXIT; - /* Settings icons*/ - case MENU_ENUM_LABEL_DRIVER_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS; - case MENU_ENUM_LABEL_VIDEO_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_VIDEO; - case MENU_ENUM_LABEL_AUDIO_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_AUDIO; - case MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_MIXER; - case MENU_ENUM_LABEL_INPUT_SETTINGS: - case MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES: - case MENU_ENUM_LABEL_INPUT_USER_1_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_2_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_3_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_4_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_5_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_6_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_7_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_8_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_9_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_10_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_11_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_12_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_13_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_14_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_15_BINDS: - case MENU_ENUM_LABEL_INPUT_USER_16_BINDS: - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS; - case MENU_ENUM_LABEL_LATENCY_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_LATENCY; - case MENU_ENUM_LABEL_SAVING_SETTINGS: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG: - case MENU_ENUM_LABEL_SAVE_NEW_CONFIG: - case MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS: - case MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS: - return OZONE_ENTRIES_ICONS_TEXTURE_SAVING; - case MENU_ENUM_LABEL_LOGGING_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_LOG; - case MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP; - case MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING: - case MENU_ENUM_LABEL_RECORDING_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_RECORD; - case MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING: - return OZONE_ENTRIES_ICONS_TEXTURE_STREAM; - case MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING: - case MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING: - case MENU_ENUM_LABEL_CHEAT_DELETE_ALL: - case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE: - case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME: - case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CONTENT_DIR: - case MENU_ENUM_LABEL_CORE_DELETE: - return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; - case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_OSD; - case MENU_ENUM_LABEL_SHOW_WIMP: - case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_UI; -#ifdef HAVE_LAKKA_SWITCH - case MENU_ENUM_LABEL_SWITCH_GPU_PROFILE: - case MENU_ENUM_LABEL_SWITCH_CPU_PROFILE: -#endif - case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_POWER; - case MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS; - case MENU_ENUM_LABEL_NETWORK_INFORMATION: - case MENU_ENUM_LABEL_NETWORK_SETTINGS: - case MENU_ENUM_LABEL_WIFI_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_NETWORK; - case MENU_ENUM_LABEL_PLAYLIST_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST; - case MENU_ENUM_LABEL_USER_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_USER; - case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: - case MENU_ENUM_LABEL_SCAN_DIRECTORY: - case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT: - return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; - case MENU_ENUM_LABEL_PRIVACY_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY; - - case MENU_ENUM_LABEL_REWIND_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_REWIND; - case MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE; - case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: - return OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS; -#ifdef HAVE_NETWORKING - case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: - return OZONE_ENTRIES_ICONS_TEXTURE_RUN; - case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: - return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; - case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: - return OZONE_ENTRIES_ICONS_TEXTURE_ROOM; - case MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS: - return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; -#endif - case MENU_ENUM_LABEL_REBOOT: - case MENU_ENUM_LABEL_RESET_TO_DEFAULT_CONFIG: - case MENU_ENUM_LABEL_CHEAT_RELOAD_CHEATS: - case MENU_ENUM_LABEL_RESTART_RETROARCH: - return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; - case MENU_ENUM_LABEL_SHUTDOWN: - return OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN; - case MENU_ENUM_LABEL_CONFIGURATIONS: - case MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS: - case MENU_ENUM_LABEL_REMAP_FILE_LOAD: - case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: - case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET: - case MENU_ENUM_LABEL_CHEAT_FILE_LOAD: - case MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND: - return OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE; - case MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES: - case MENU_ENUM_LABEL_SHADER_APPLY_CHANGES: - return OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK; - default: - break; - } - - switch(type) - { - case FILE_TYPE_DIRECTORY: - return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; - case FILE_TYPE_PLAIN: - case FILE_TYPE_IN_CARCHIVE: - case FILE_TYPE_RPL_ENTRY: - return OZONE_ENTRIES_ICONS_TEXTURE_FILE; - case FILE_TYPE_SHADER: - case FILE_TYPE_SHADER_PRESET: - return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; - case FILE_TYPE_CARCHIVE: - return OZONE_ENTRIES_ICONS_TEXTURE_ZIP; - case FILE_TYPE_MUSIC: - return OZONE_ENTRIES_ICONS_TEXTURE_MUSIC; - case FILE_TYPE_IMAGE: - case FILE_TYPE_IMAGEVIEWER: - return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; - case FILE_TYPE_MOVIE: - return OZONE_ENTRIES_ICONS_TEXTURE_MOVIE; - case FILE_TYPE_CORE: - case FILE_TYPE_DIRECT_LOAD: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE; - case FILE_TYPE_RDB: - return OZONE_ENTRIES_ICONS_TEXTURE_RDB; - case FILE_TYPE_CURSOR: - return OZONE_ENTRIES_ICONS_TEXTURE_CURSOR; - case FILE_TYPE_PLAYLIST_ENTRY: - case MENU_SETTING_ACTION_RUN: - case MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS: - return OZONE_ENTRIES_ICONS_TEXTURE_RUN; - case MENU_SETTING_ACTION_CLOSE: - case MENU_SETTING_ACTION_DELETE_ENTRY: - return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; - case MENU_SETTING_ACTION_SAVESTATE: - return OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE; - case MENU_SETTING_ACTION_LOADSTATE: - return OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE; - case FILE_TYPE_RDB_ENTRY: - case MENU_SETTING_ACTION_CORE_INFORMATION: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; - case MENU_SETTING_ACTION_CORE_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS; - case MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS; - case MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; - case MENU_SETTING_ACTION_CORE_DISK_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS; - case MENU_SETTING_ACTION_CORE_SHADER_OPTIONS: - return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; - case MENU_SETTING_ACTION_SCREENSHOT: - return OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT; - case MENU_SETTING_ACTION_RESET: - return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; - case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: - return OZONE_ENTRIES_ICONS_TEXTURE_RESUME; - - case MENU_SETTING_GROUP: -#ifdef HAVE_LAKKA_SWITCH - case MENU_SET_SWITCH_BRIGHTNESS: -#endif - return OZONE_ENTRIES_ICONS_TEXTURE_SETTING; - case MENU_INFO_MESSAGE: - return OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; - case MENU_WIFI: - return OZONE_ENTRIES_ICONS_TEXTURE_WIFI; -#ifdef HAVE_NETWORKING - case MENU_ROOM: - return OZONE_ENTRIES_ICONS_TEXTURE_ROOM; - case MENU_ROOM_LAN: - return OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN; - case MENU_ROOM_RELAY: - return OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY; -#endif - case MENU_SETTING_ACTION: - return OZONE_ENTRIES_ICONS_TEXTURE_SETTING; - } - -#ifdef HAVE_CHEEVOS - if ( - (type >= MENU_SETTINGS_CHEEVOS_START) && - (type < MENU_SETTINGS_NETPLAY_ROOMS_START) - ) - { - int new_id = type - MENU_SETTINGS_CHEEVOS_START; - if (get_badge_texture(new_id) != 0) - return get_badge_texture(new_id); - /* Should be replaced with placeholder badge icon. */ - return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS; - } -#endif - - if ( - (type >= MENU_SETTINGS_INPUT_BEGIN) && - (type <= MENU_SETTINGS_INPUT_DESC_END) - ) - { - unsigned input_id; - if (type < MENU_SETTINGS_INPUT_DESC_BEGIN) - { - input_id = MENU_SETTINGS_INPUT_BEGIN; - if ( type == input_id + 2) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS; - if ( type == input_id + 4) - return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; - if ( type == input_id + 5) - return OZONE_ENTRIES_ICONS_TEXTURE_SAVING; - input_id = input_id + 7; - } - else - { - input_id = MENU_SETTINGS_INPUT_DESC_BEGIN; - while (type > (input_id + 23)) - { - input_id = (input_id + 24) ; - } - } - if ( type == input_id ) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D; - if ( type == (input_id + 1)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L; - if ( type == (input_id + 2)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT; - if ( type == (input_id + 3)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START; - if ( type == (input_id + 4)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U; - if ( type == (input_id + 5)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D; - if ( type == (input_id + 6)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L; - if ( type == (input_id + 7)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R; - if ( type == (input_id + 8)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R; - if ( type == (input_id + 9)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U; - if ( type == (input_id + 10)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB; - if ( type == (input_id + 11)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB; - if ( type == (input_id + 12)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT; - if ( type == (input_id + 13)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT; - if ( type == (input_id + 14)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P; - if ( type == (input_id + 15)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P; - if ( type == (input_id + 16)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R; - if ( type == (input_id + 17)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L; - if ( type == (input_id + 18)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D; - if ( type == (input_id + 19)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U; - if ( type == (input_id + 20)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R; - if ( type == (input_id + 21)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L; - if ( type == (input_id + 22)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D; - if ( type == (input_id + 23)) - return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U; - } - return OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING; -} - -static void ozone_draw_text( - video_frame_info_t *video_info, - ozone_handle_t *ozone, - const char *str, float x, - float y, - enum text_alignment text_align, - unsigned width, unsigned height, font_data_t* font, - uint32_t color, - bool draw_outside) -{ - if ((color & 0x000000FF) == 0) - return; - - menu_display_draw_text(font, str, x, y, - width, height, color, text_align, 1.0f, - false, - 1.0, draw_outside); -} - -static void ozone_unload_theme_textures(ozone_handle_t *ozone) -{ - int i; - int j; - - for (j = 0; j < ozone_themes_count; j++) - { - ozone_theme_t *theme = ozone_themes[j]; - for (i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) - video_driver_texture_unload(&theme->textures[i]); - } -} - -static bool ozone_reset_theme_textures(ozone_handle_t *ozone) -{ - int i; - int j; - char theme_path[255]; - bool result = true; - - for (j = 0; j < ozone_themes_count; j++) - { - ozone_theme_t *theme = ozone_themes[j]; - - fill_pathname_join( - theme_path, - ozone->png_path, - theme->name, - sizeof(theme_path) - ); - - for (i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) - { - char filename[PATH_MAX_LENGTH]; - strlcpy(filename, OZONE_THEME_TEXTURES_FILES[i], sizeof(filename)); - strlcat(filename, ".png", sizeof(filename)); - - if (!menu_display_reset_textures_list(filename, theme_path, &theme->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) - result = false; - } - } - - return result; -} - -static void ozone_cursor_animation_cb(void *userdata); - -static void ozone_animate_cursor(ozone_handle_t *ozone, float *dst, float *target) -{ - menu_animation_ctx_entry_t entry; - int i; - - entry.easing_enum = EASING_OUT_QUAD; - entry.tag = (uintptr_t) &ozone_default_theme; - entry.duration = ANIMATION_CURSOR_PULSE; - entry.userdata = ozone; - - for (i = 0; i < 16; i++) - { - if (i == 3 || i == 7 || i == 11 || i == 15) - continue; - - if (i == 14) - entry.cb = ozone_cursor_animation_cb; - else - entry.cb = NULL; - - entry.subject = &dst[i]; - entry.target_value = target[i]; - - menu_animation_push(&entry); - } -} - -static void ozone_cursor_animation_cb(void *userdata) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - - float *target = NULL; - - switch (ozone->theme_dynamic.cursor_state) - { - case 0: - target = ozone->theme->cursor_border_1; - break; - case 1: - target = ozone->theme->cursor_border_0; - break; - } - - ozone->theme_dynamic.cursor_state = (ozone->theme_dynamic.cursor_state + 1) % 2; - - ozone_animate_cursor(ozone, ozone->theme_dynamic.cursor_border, target); -} - -static void ozone_restart_cursor_animation(ozone_handle_t *ozone) -{ - menu_animation_ctx_tag tag = (uintptr_t) &ozone_default_theme; - - if (!ozone->has_all_assets) - return; - - ozone->theme_dynamic.cursor_state = 1; - memcpy(ozone->theme_dynamic.cursor_border, ozone->theme->cursor_border_0, sizeof(ozone->theme_dynamic.cursor_border)); - menu_animation_kill_by_tag(&tag); - - ozone_animate_cursor(ozone, ozone->theme_dynamic.cursor_border, ozone->theme->cursor_border_1); -} - -static void ozone_set_color_theme(ozone_handle_t *ozone, unsigned color_theme) -{ - ozone_theme_t *theme = ozone_default_theme; - - if (!ozone) - return; - - switch (color_theme) - { - case 1: - theme = &ozone_theme_dark; - break; - case 0: - default: - break; - } - - ozone->theme = theme; - - memcpy(ozone->theme_dynamic.selection_border, ozone->theme->selection_border, sizeof(ozone->theme_dynamic.selection_border)); - memcpy(ozone->theme_dynamic.selection, ozone->theme->selection, sizeof(ozone->theme_dynamic.selection)); - memcpy(ozone->theme_dynamic.entries_border, ozone->theme->entries_border, sizeof(ozone->theme_dynamic.entries_border)); - memcpy(ozone->theme_dynamic.entries_icon, ozone->theme->entries_icon, sizeof(ozone->theme_dynamic.entries_icon)); - memcpy(ozone->theme_dynamic.entries_checkmark, ozone_pure_white, sizeof(ozone->theme_dynamic.entries_checkmark)); - memcpy(ozone->theme_dynamic.cursor_alpha, ozone_pure_white, sizeof(ozone->theme_dynamic.cursor_alpha)); - memcpy(ozone->theme_dynamic.message_background, ozone->theme->message_background, sizeof(ozone->theme_dynamic.message_background)); - - ozone_restart_cursor_animation(ozone); - - last_color_theme = color_theme; -} - -static ozone_node_t *ozone_alloc_node() -{ - ozone_node_t *node = (ozone_node_t*)malloc(sizeof(*node)); - - node->height = 0; - node->position_y = 0; - node->console_name = NULL; - node->icon = 0; - node->content_icon = 0; - - return node; -} - -static size_t ozone_list_get_size(void *data, enum menu_list_type type) -{ - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (!ozone) - return 0; - - switch (type) - { - case MENU_LIST_PLAIN: - return menu_entries_get_stack_size(0); - case MENU_LIST_HORIZONTAL: - if (ozone && ozone->horizontal_list) - return file_list_get_size(ozone->horizontal_list); - break; - case MENU_LIST_TABS: - return ozone->system_tab_end; - } - - return 0; -} - -static void ozone_context_reset_horizontal_list(ozone_handle_t *ozone) -{ - unsigned i; - const char *title; - char title_noext[255]; - - size_t list_size = ozone_list_get_size(ozone, MENU_LIST_HORIZONTAL); - - for (i = 0; i < list_size; i++) - { - const char *path = NULL; - ozone_node_t *node = (ozone_node_t*)file_list_get_userdata_at_offset(ozone->horizontal_list, i); - - if (!node) - { - node = ozone_alloc_node(); - if (!node) - continue; - } - - file_list_get_at_offset(ozone->horizontal_list, i, - &path, NULL, NULL, NULL); - - if (!path) - continue; - - if (!strstr(path, file_path_str(FILE_PATH_LPL_EXTENSION))) - continue; - - { - struct texture_image ti; - char *sysname = (char*) - malloc(PATH_MAX_LENGTH * sizeof(char)); - char *texturepath = (char*) - malloc(PATH_MAX_LENGTH * sizeof(char)); - char *content_texturepath = (char*) - malloc(PATH_MAX_LENGTH * sizeof(char)); - char *icons_path = (char*) - malloc(PATH_MAX_LENGTH * sizeof(char)); - - strlcpy(icons_path, ozone->icons_path, PATH_MAX_LENGTH * sizeof(char)); - - sysname[0] = texturepath[0] = content_texturepath[0] = '\0'; - - fill_pathname_base_noext(sysname, path, - PATH_MAX_LENGTH * sizeof(char)); - - fill_pathname_join_concat(texturepath, icons_path, sysname, - file_path_str(FILE_PATH_PNG_EXTENSION), - PATH_MAX_LENGTH * sizeof(char)); - - /* If the playlist icon doesn't exist return default */ - - if (!filestream_exists(texturepath)) - fill_pathname_join_concat(texturepath, icons_path, "default", - file_path_str(FILE_PATH_PNG_EXTENSION), - PATH_MAX_LENGTH * sizeof(char)); - - ti.width = 0; - ti.height = 0; - ti.pixels = NULL; - ti.supports_rgba = video_driver_supports_rgba(); - - if (image_texture_load(&ti, texturepath)) - { - if(ti.pixels) - { - video_driver_texture_unload(&node->icon); - video_driver_texture_load(&ti, - TEXTURE_FILTER_MIPMAP_LINEAR, &node->icon); - } - - image_texture_free(&ti); - } - - fill_pathname_join_delim(sysname, sysname, - file_path_str(FILE_PATH_CONTENT_BASENAME), '-', - PATH_MAX_LENGTH * sizeof(char)); - strlcat(content_texturepath, icons_path, PATH_MAX_LENGTH * sizeof(char)); - - strlcat(content_texturepath, path_default_slash(), PATH_MAX_LENGTH * sizeof(char)); - strlcat(content_texturepath, sysname, PATH_MAX_LENGTH * sizeof(char)); - - /* If the content icon doesn't exist return default-content */ - if (!filestream_exists(content_texturepath)) - { - strlcat(icons_path, path_default_slash(), PATH_MAX_LENGTH * sizeof(char)); - strlcat(icons_path, "default", PATH_MAX_LENGTH * sizeof(char)); - fill_pathname_join_delim(content_texturepath, icons_path, - file_path_str(FILE_PATH_CONTENT_BASENAME), '-', - PATH_MAX_LENGTH * sizeof(char)); - } - - if (image_texture_load(&ti, content_texturepath)) - { - if(ti.pixels) - { - video_driver_texture_unload(&node->content_icon); - video_driver_texture_load(&ti, - TEXTURE_FILTER_MIPMAP_LINEAR, &node->content_icon); - } - - image_texture_free(&ti); - } - - /* Console name */ - menu_entries_get_at_offset( - ozone->horizontal_list, - i, - &title, NULL, NULL, NULL, NULL); - - fill_pathname_base_noext(title_noext, title, sizeof(title_noext)); - - /* Format : "Vendor - Console" - Remove everything before the hyphen - and the subsequent space */ - char *chr = title_noext; - bool hyphen_found = false; - - while (true) - { - if (*chr == '-') - { - hyphen_found = true; - break; - } - else if (*chr == '\0') - break; - - chr++; - } - - if (hyphen_found) - chr += 2; - else - chr = title_noext; - - node->console_name = strdup(chr); - - free(sysname); - free(texturepath); - free(content_texturepath); - free(icons_path); - } - } -} - -static void ozone_context_destroy_horizontal_list(ozone_handle_t *ozone) -{ - unsigned i; - size_t list_size = ozone_list_get_size(ozone, MENU_LIST_HORIZONTAL); - - for (i = 0; i < list_size; i++) - { - const char *path = NULL; - ozone_node_t *node = (ozone_node_t*)file_list_get_userdata_at_offset(ozone->horizontal_list, i); - - if (!node) - continue; - - file_list_get_at_offset(ozone->horizontal_list, i, - &path, NULL, NULL, NULL); - - if (!path || !strstr(path, file_path_str(FILE_PATH_LPL_EXTENSION))) - continue; - - video_driver_texture_unload(&node->icon); - video_driver_texture_unload(&node->content_icon); - } -} - -static void ozone_free_node(ozone_node_t *node) -{ - if (!node) - return; - - if (node->console_name) - free(node->console_name); - - free(node); -} - -static void ozone_free_list_nodes(file_list_t *list, bool actiondata) -{ - unsigned i, size = (unsigned)file_list_get_size(list); - - for (i = 0; i < size; ++i) - { - ozone_free_node((ozone_node_t*)file_list_get_userdata_at_offset(list, i)); - - /* file_list_set_userdata() doesn't accept NULL */ - list->list[i].userdata = NULL; - - if (actiondata) - file_list_free_actiondata(list, i); - } -} - - -static void ozone_init_horizontal_list(ozone_handle_t *ozone) -{ - menu_displaylist_info_t info; - settings_t *settings = config_get_ptr(); - - menu_displaylist_info_init(&info); - - info.list = ozone->horizontal_list; - info.path = strdup( - settings->paths.directory_playlist); - info.label = strdup( - msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST)); - info.exts = strdup( - file_path_str(FILE_PATH_LPL_EXTENSION_NO_DOT)); - info.type_default = FILE_TYPE_PLAIN; - info.enum_idx = MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST; - - if (settings->bools.menu_content_show_playlists && !string_is_empty(info.path)) - { - if (menu_displaylist_ctl(DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL, &info)) - { - size_t i; - for (i = 0; i < ozone->horizontal_list->size; i++) - { - ozone_node_t *node = ozone_alloc_node(); - file_list_set_userdata(ozone->horizontal_list, i, node); - } - - menu_displaylist_process(&info); - } - } - - menu_displaylist_info_free(&info); -} - -static void ozone_refresh_horizontal_list(ozone_handle_t *ozone) -{ - ozone_context_destroy_horizontal_list(ozone); - if (ozone->horizontal_list) - { - ozone_free_list_nodes(ozone->horizontal_list, false); - file_list_free(ozone->horizontal_list); - } - ozone->horizontal_list = NULL; - - menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); - - ozone->horizontal_list = (file_list_t*) - calloc(1, sizeof(file_list_t)); - - if (ozone->horizontal_list) - ozone_init_horizontal_list(ozone); - - ozone_context_reset_horizontal_list(ozone); -} - -static void *ozone_init(void **userdata, bool video_is_threaded) -{ - bool fallback_color_theme = false; - unsigned width, height, color_theme = 0; - ozone_handle_t *ozone = NULL; - settings_t *settings = config_get_ptr(); - menu_handle_t *menu = (menu_handle_t*)calloc(1, sizeof(*menu)); - - if (!menu) - return false; - - if (!menu_display_init_first_driver(video_is_threaded)) - goto error; - - video_driver_get_size(&width, &height); - - ozone = (ozone_handle_t*)calloc(1, sizeof(ozone_handle_t)); - - if (!ozone) - goto error; - - *userdata = ozone; - - ozone->selection_buf_old = (file_list_t*)calloc(1, sizeof(file_list_t)); - - ozone->draw_sidebar = true; - ozone->sidebar_offset = 0; - ozone->pending_message = NULL; - ozone->is_playlist = false; - ozone->categories_selection_ptr = 0; - ozone->pending_message = NULL; - - ozone->system_tab_end = 0; - ozone->tabs[ozone->system_tab_end] = OZONE_SYSTEM_TAB_MAIN; - if (settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_SETTINGS; - if (settings->bools.menu_content_show_favorites) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_FAVORITES; - if (settings->bools.menu_content_show_history) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_HISTORY; -#ifdef HAVE_IMAGEVIEWERe - if (settings->bools.menu_content_show_images) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_IMAGES; -#endif - if (settings->bools.menu_content_show_music) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_MUSIC; -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - if (settings->bools.menu_content_show_video) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_VIDEO; -#endif -#ifdef HAVE_NETWORKING - if (settings->bools.menu_content_show_netplay) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_NETPLAY; -#endif -#ifdef HAVE_LIBRETRODB - if (settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_ADD; -#endif - - menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); - - menu_display_set_width(width); - menu_display_set_height(height); - - menu_display_allocate_white_texture(); - - ozone->horizontal_list = (file_list_t*)calloc(1, sizeof(file_list_t)); - - if (ozone->horizontal_list) - ozone_init_horizontal_list(ozone); - - /* Theme */ - if (settings->bools.menu_use_preferred_system_color_theme) - { -#ifdef HAVE_LIBNX - if (R_SUCCEEDED(setsysInitialize())) - { - ColorSetId theme; - setsysGetColorSetId(&theme); - color_theme = (theme == ColorSetId_Dark) ? 1 : 0; - ozone_set_color_theme(ozone, color_theme); - settings->uints.menu_ozone_color_theme = color_theme; - settings->bools.menu_preferred_system_color_theme_set = true; - setsysExit(); - } - else - fallback_color_theme = true; -#endif - } - else - fallback_color_theme = true; - - if (fallback_color_theme) - { - color_theme = settings->uints.menu_ozone_color_theme; - ozone_set_color_theme(ozone, color_theme); - } - - ozone->need_compute = false; - ozone->animations.scroll_y = 0.0f; - ozone->animations.scroll_y_sidebar = 0.0f; - - /* Assets path */ - fill_pathname_join( - ozone->assets_path, - settings->paths.directory_assets, - "ozone", - sizeof(ozone->assets_path) - ); - - /* PNG path */ - fill_pathname_join( - ozone->png_path, - ozone->assets_path, - "png", - sizeof(ozone->png_path) - ); - - /* Icons path */ - fill_pathname_join( - ozone->icons_path, - ozone->png_path, - "icons", - sizeof(ozone->icons_path) - ); - - /* Sidebar path */ - fill_pathname_join( - ozone->tab_path, - ozone->png_path, - "sidebar", - sizeof(ozone->tab_path) - ); - - last_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme; - - return menu; - -error: - if (ozone->horizontal_list) - { - ozone_free_list_nodes(ozone->horizontal_list, false); - file_list_free(ozone->horizontal_list); - } - ozone->horizontal_list = NULL; - - if (menu) - free(menu); - - return NULL; -} - -static void ozone_free(void *data) -{ - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (ozone) - { - video_coord_array_free(&ozone->raster_blocks.footer.carr); - video_coord_array_free(&ozone->raster_blocks.title.carr); - video_coord_array_free(&ozone->raster_blocks.time.carr); - video_coord_array_free(&ozone->raster_blocks.entries_label.carr); - video_coord_array_free(&ozone->raster_blocks.entries_sublabel.carr); - video_coord_array_free(&ozone->raster_blocks.sidebar.carr); - - font_driver_bind_block(NULL, NULL); - - if (ozone->selection_buf_old) - { - ozone_free_list_nodes(ozone->selection_buf_old, false); - file_list_free(ozone->selection_buf_old); - } - - if (ozone->horizontal_list) - { - ozone_free_list_nodes(ozone->horizontal_list, false); - file_list_free(ozone->horizontal_list); - } - - if (!string_is_empty(ozone->pending_message)) - free(ozone->pending_message); - } -} - -static void ozone_context_reset(void *data, bool is_threaded) -{ - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (ozone) - { - ozone->has_all_assets = true; - - /* Fonts init */ - unsigned i; - unsigned size; - char font_path[PATH_MAX_LENGTH]; - - fill_pathname_join(font_path, ozone->assets_path, "regular.ttf", sizeof(font_path)); - ozone->fonts.footer = menu_display_font_file(font_path, FONT_SIZE_FOOTER, is_threaded); - ozone->fonts.entries_label = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_LABEL, is_threaded); - ozone->fonts.entries_sublabel = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_SUBLABEL, is_threaded); - ozone->fonts.time = menu_display_font_file(font_path, FONT_SIZE_TIME, is_threaded); - ozone->fonts.sidebar = menu_display_font_file(font_path, FONT_SIZE_SIDEBAR, is_threaded); - - fill_pathname_join(font_path, ozone->assets_path, "bold.ttf", sizeof(font_path)); - ozone->fonts.title = menu_display_font_file(font_path, FONT_SIZE_TITLE, is_threaded); - - if ( - !ozone->fonts.footer || - !ozone->fonts.entries_label || - !ozone->fonts.entries_sublabel || - !ozone->fonts.time || - !ozone->fonts.sidebar || - !ozone->fonts.title - ) - { - ozone->has_all_assets = false; - } - - /* Naive font size */ - ozone->title_font_glyph_width = FONT_SIZE_TITLE * 3/4; - ozone->entry_font_glyph_width = FONT_SIZE_ENTRIES_LABEL * 3/4; - ozone->sublabel_font_glyph_width = FONT_SIZE_ENTRIES_SUBLABEL * 3/4; - - /* More realistic font size */ - size = font_driver_get_message_width(ozone->fonts.title, "a", 1, 1); - if (size) - ozone->title_font_glyph_width = size; - size = font_driver_get_message_width(ozone->fonts.entries_label, "a", 1, 1); - if (size) - ozone->entry_font_glyph_width = size; - size = font_driver_get_message_width(ozone->fonts.entries_sublabel, "a", 1, 1); - if (size) - ozone->sublabel_font_glyph_width = size; - - /* Textures init */ - for (i = 0; i < OZONE_TEXTURE_LAST; i++) - { - char filename[PATH_MAX_LENGTH]; - strlcpy(filename, OZONE_TEXTURES_FILES[i], sizeof(filename)); - strlcat(filename, ".png", sizeof(filename)); - - if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) - ozone->has_all_assets = false; - } - - /* Sidebar textures */ - for (i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) - { - char filename[PATH_MAX_LENGTH]; - strlcpy(filename, OZONE_TAB_TEXTURES_FILES[i], sizeof(filename)); - strlcat(filename, ".png", sizeof(filename)); - - if (!menu_display_reset_textures_list(filename, ozone->tab_path, &ozone->tab_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) - ozone->has_all_assets = false; - } - - /* Theme textures */ - if (!ozone_reset_theme_textures(ozone)) - ozone->has_all_assets = false; - - /* Icons textures init */ - for (i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) - if (!menu_display_reset_textures_list(ozone_entries_icon_texture_path(ozone, i), ozone->icons_path, &ozone->icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) - ozone->has_all_assets = false; - - menu_display_allocate_white_texture(); - - /* Horizontal list */ - ozone_context_reset_horizontal_list(ozone); - - /* State reset */ - ozone->frame_count = 0; - ozone->fade_direction = false; - ozone->cursor_in_sidebar = false; - ozone->cursor_in_sidebar_old = false; - ozone->draw_old_list = false; - ozone->messagebox_state = false; - ozone->messagebox_state_old = false; - - /* Animations */ - ozone->animations.cursor_alpha = 1.0f; - ozone->animations.scroll_y = 0.0f; - ozone->animations.list_alpha = 1.0f; - - /* Missing assets message */ - /* TODO Localize */ - if (!ozone->has_all_assets) - runloop_msg_queue_push("Some assets are missing - please update them", 1, 256, false); - - ozone_restart_cursor_animation(ozone); - } -} - -static void ozone_collapse_end(void *userdata) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - ozone->draw_sidebar = false; -} - -static void ozone_context_destroy(void *data) -{ - unsigned i; - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (!ozone) - return; - - /* Theme */ - ozone_unload_theme_textures(ozone); - - /* Icons */ - for (i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) - video_driver_texture_unload(&ozone->icons_textures[i]); - - /* Textures */ - for (i = 0; i < OZONE_TEXTURE_LAST; i++) - video_driver_texture_unload(&ozone->textures[i]); - - /* Icons */ - for (i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) - video_driver_texture_unload(&ozone->tab_textures[i]); - - video_driver_texture_unload(&menu_display_white_texture); - - menu_display_font_free(ozone->fonts.footer); - menu_display_font_free(ozone->fonts.title); - menu_display_font_free(ozone->fonts.time); - menu_display_font_free(ozone->fonts.entries_label); - menu_display_font_free(ozone->fonts.entries_sublabel); - menu_display_font_free(ozone->fonts.sidebar); - - ozone->fonts.footer = NULL; - ozone->fonts.title = NULL; - ozone->fonts.time = NULL; - ozone->fonts.entries_label = NULL; - ozone->fonts.entries_sublabel = NULL; - ozone->fonts.sidebar = NULL; - - menu_animation_ctx_tag tag = (uintptr_t) &ozone_default_theme; - menu_animation_kill_by_tag(&tag); - - /* Horizontal list */ - ozone_context_destroy_horizontal_list(ozone); -} - -static void *ozone_list_get_entry(void *data, - enum menu_list_type type, unsigned i) -{ - size_t list_size = 0; - ozone_handle_t* ozone = (ozone_handle_t*) data; - - switch (type) - { - case MENU_LIST_PLAIN: - { - file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); - list_size = menu_entries_get_stack_size(0); - if (i < list_size) - return (void*)&menu_stack->list[i]; - } - break; - case MENU_LIST_HORIZONTAL: - if (ozone && ozone->horizontal_list) - list_size = file_list_get_size(ozone->horizontal_list); - if (i < list_size) - return (void*)&ozone->horizontal_list->list[i]; - break; - default: - break; - } - - return NULL; -} - -static int ozone_list_push(void *data, void *userdata, - menu_displaylist_info_t *info, unsigned type) -{ - menu_displaylist_ctx_parse_entry_t entry; - int ret = -1; - unsigned i = 0; - core_info_list_t *list = NULL; - menu_handle_t *menu = (menu_handle_t*)data; - - switch (type) - { - case DISPLAYLIST_LOAD_CONTENT_LIST: - { - settings_t *settings = config_get_ptr(); - - menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); - - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), - msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), - MENU_ENUM_LABEL_FAVORITES, - MENU_SETTING_ACTION, 0, 0); - - core_info_get_list(&list); - if (core_info_list_num_info_files(list)) - { - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), - MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, - MENU_SETTING_ACTION, 0, 0); - } - -#ifdef HAVE_LIBRETRODB - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST), - MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST, - MENU_SETTING_ACTION, 0, 0); -#endif - - if (frontend_driver_parse_drive_list(info->list, true) != 0) - menu_entries_append_enum(info->list, "/", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, - MENU_SETTING_ACTION, 0, 0); - - if (!settings->bools.kiosk_mode_enable) - { - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), - MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, - MENU_SETTING_ACTION, 0, 0); - } - - info->need_push = true; - info->need_refresh = true; - ret = 0; - } - break; - case DISPLAYLIST_MAIN_MENU: - { - settings_t *settings = config_get_ptr(); - rarch_system_info_t *system = runloop_get_system_info(); - menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); - - entry.data = menu; - entry.info = info; - entry.parse_type = PARSE_ACTION; - entry.add_empty_entry = false; - - if (!string_is_empty(system->info.library_name) && - !string_is_equal(system->info.library_name, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE))) - { - entry.enum_idx = MENU_ENUM_LABEL_CONTENT_SETTINGS; - menu_displaylist_setting(&entry); - } - - if (system->load_no_content) - { - entry.enum_idx = MENU_ENUM_LABEL_START_CORE; - menu_displaylist_setting(&entry); - } - -#ifndef HAVE_DYNAMIC - if (frontend_driver_has_fork()) -#endif - { - if (settings->bools.menu_show_load_core) - { - entry.enum_idx = MENU_ENUM_LABEL_CORE_LIST; - menu_displaylist_setting(&entry); - } - } - - if (settings->bools.menu_show_load_content) - { - const struct retro_subsystem_info* subsystem = NULL; - - entry.enum_idx = MENU_ENUM_LABEL_LOAD_CONTENT_LIST; - menu_displaylist_setting(&entry); - - subsystem = system->subsystem.data; - - if (subsystem) - { - for (i = 0; i < (unsigned)system->subsystem.size; i++, subsystem++) - { - char s[PATH_MAX_LENGTH]; - if (content_get_subsystem() == i) - { - if (content_get_subsystem_rom_id() < subsystem->num_roms) - { - snprintf(s, sizeof(s), - "Load %s %s", - subsystem->desc, - i == content_get_subsystem() - ? "\u2605" : " "); - menu_entries_append_enum(info->list, - s, - msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), - MENU_ENUM_LABEL_SUBSYSTEM_ADD, - MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); - } - else - { - snprintf(s, sizeof(s), - "Start %s %s", - subsystem->desc, - i == content_get_subsystem() - ? "\u2605" : " "); - menu_entries_append_enum(info->list, - s, - msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_LOAD), - MENU_ENUM_LABEL_SUBSYSTEM_LOAD, - MENU_SETTINGS_SUBSYSTEM_LOAD, 0, 0); - } - } - else - { - snprintf(s, sizeof(s), - "Load %s %s", - subsystem->desc, - i == content_get_subsystem() - ? "\u2605" : " "); - menu_entries_append_enum(info->list, - s, - msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), - MENU_ENUM_LABEL_SUBSYSTEM_ADD, - MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); - } - } - } - } - - entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; - menu_displaylist_setting(&entry); -#ifdef HAVE_QT - if (settings->bools.desktop_menu_enable) - { - entry.enum_idx = MENU_ENUM_LABEL_SHOW_WIMP; - menu_displaylist_setting(&entry); - } -#endif -#if defined(HAVE_NETWORKING) - if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable) - { - entry.enum_idx = MENU_ENUM_LABEL_ONLINE_UPDATER; - menu_displaylist_setting(&entry); - } -#endif - if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password)) - { - entry.enum_idx = MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS; - menu_displaylist_setting(&entry); - } - - if (settings->bools.kiosk_mode_enable && !string_is_empty(settings->paths.kiosk_mode_password)) - { - entry.enum_idx = MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE; - menu_displaylist_setting(&entry); - } - - if (settings->bools.menu_show_information) - { - entry.enum_idx = MENU_ENUM_LABEL_INFORMATION_LIST; - menu_displaylist_setting(&entry); - } - -#ifdef HAVE_LAKKA_SWITCH - entry.enum_idx = MENU_ENUM_LABEL_SWITCH_CPU_PROFILE; - menu_displaylist_setting(&entry); - - entry.enum_idx = MENU_ENUM_LABEL_SWITCH_GPU_PROFILE; - menu_displaylist_setting(&entry); - - entry.enum_idx = MENU_ENUM_LABEL_SWITCH_BACKLIGHT_CONTROL; - menu_displaylist_setting(&entry); -#endif - -#ifndef HAVE_DYNAMIC - entry.enum_idx = MENU_ENUM_LABEL_RESTART_RETROARCH; - menu_displaylist_setting(&entry); -#endif - - if (settings->bools.menu_show_configurations && !settings->bools.kiosk_mode_enable) - { - entry.enum_idx = MENU_ENUM_LABEL_CONFIGURATIONS_LIST; - menu_displaylist_setting(&entry); - } - - if (settings->bools.menu_show_help) - { - entry.enum_idx = MENU_ENUM_LABEL_HELP_LIST; - menu_displaylist_setting(&entry); - } - -#if !defined(IOS) - if (settings->bools.menu_show_quit_retroarch) - { - entry.enum_idx = MENU_ENUM_LABEL_QUIT_RETROARCH; - menu_displaylist_setting(&entry); - } -#endif - - if (settings->bools.menu_show_reboot) - { - entry.enum_idx = MENU_ENUM_LABEL_REBOOT; - menu_displaylist_setting(&entry); - } - - if (settings->bools.menu_show_shutdown) - { - entry.enum_idx = MENU_ENUM_LABEL_SHUTDOWN; - menu_displaylist_setting(&entry); - } - - info->need_push = true; - ret = 0; - } - break; - } - return ret; -} - -static size_t ozone_list_get_selection(void *data) -{ - ozone_handle_t *ozone = (ozone_handle_t*)data; - - if (!ozone) - return 0; - - return ozone->categories_selection_ptr; -} - -static void ozone_list_clear(file_list_t *list) -{ - menu_animation_ctx_tag tag = (uintptr_t)list; - menu_animation_kill_by_tag(&tag); - - ozone_free_list_nodes(list, false); -} - -static void ozone_list_free(file_list_t *list, size_t a, size_t b) -{ - ozone_list_clear(list); -} - -/* Compute new scroll position - * If the center of the currently selected entry is not in the middle - * And if we can scroll so that it's in the middle - * Then scroll - */ -static void ozone_update_scroll(ozone_handle_t *ozone, bool allow_animation, ozone_node_t *node) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_animation_ctx_tag tag = (uintptr_t) selection_buf; - menu_animation_ctx_entry_t entry; - float new_scroll = 0, entries_middle; - float bottom_boundary, current_selection_middle_onscreen; - unsigned video_info_height; - - video_driver_get_size(NULL, &video_info_height); - - current_selection_middle_onscreen = ENTRIES_START_Y + ozone->animations.scroll_y + node->position_y + node->height / 2; - bottom_boundary = video_info_height - 87 - 78; - entries_middle = video_info_height/2; - - if (current_selection_middle_onscreen != entries_middle) - new_scroll = ozone->animations.scroll_y - (current_selection_middle_onscreen - entries_middle); - - if (new_scroll + ozone->entries_height < bottom_boundary) - new_scroll = -(78 + ozone->entries_height - bottom_boundary); - - if (new_scroll > 0) - new_scroll = 0; - - if (allow_animation) - { - /* Cursor animation */ - ozone->animations.cursor_alpha = 0.0f; - - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.cursor_alpha; - entry.tag = tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); - - /* Scroll animation */ - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.scroll_y; - entry.tag = tag; - entry.target_value = new_scroll; - entry.userdata = NULL; - - menu_animation_push(&entry); - } - else - { - ozone->selection_old = ozone->selection; - ozone->animations.cursor_alpha = 1.0f; - ozone->animations.scroll_y = new_scroll; - } -} - -static unsigned ozone_count_lines(const char *str) -{ - unsigned c = 0; - unsigned lines = 1; - - for (c = 0; str[c]; c++) - lines += (str[c] == '\n'); - return lines; -} - -static bool ozone_is_playlist(ozone_handle_t *ozone) -{ - bool is_playlist; - - switch (ozone->categories_selection_ptr) - { - case OZONE_SYSTEM_TAB_MAIN: - case OZONE_SYSTEM_TAB_SETTINGS: - case OZONE_SYSTEM_TAB_ADD: - is_playlist = false; - break; - case OZONE_SYSTEM_TAB_HISTORY: - case OZONE_SYSTEM_TAB_FAVORITES: - case OZONE_SYSTEM_TAB_MUSIC: -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - case OZONE_SYSTEM_TAB_VIDEO: -#endif -#ifdef HAVE_IMAGEVIEWER - case OZONE_SYSTEM_TAB_IMAGES: -#endif -#ifdef HAVE_NETWORKING - case OZONE_SYSTEM_TAB_NETPLAY: -#endif - default: - is_playlist = true; - break; - } - - return is_playlist && ozone->depth == 1; -} - -static void ozone_compute_entries_position(ozone_handle_t *ozone) -{ - /* Compute entries height and adjust scrolling if needed */ - unsigned video_info_height; - unsigned video_info_width; - size_t i, entries_end; - file_list_t *selection_buf = NULL; - - menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); - - entries_end = menu_entries_get_size(); - selection_buf = menu_entries_get_selection_buf_ptr(0); - - video_driver_get_size(&video_info_width, &video_info_height); - - ozone->entries_height = 0; - - for (i = 0; i < entries_end; i++) - { - /* Entry */ - menu_entry_t entry; - ozone_node_t *node = NULL; - - menu_entry_init(&entry); - menu_entry_get(&entry, 0, (unsigned)i, NULL, true); - - /* Empty playlist detection: - only one item which icon is - OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO */ - if (ozone->is_playlist && entries_end == 1) - { - unsigned icon = ozone_entries_icon_get_id(ozone, entry.enum_idx, entry.type, false); - ozone->empty_playlist = icon == OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; - } - else - { - ozone->empty_playlist = false; - } - - /* Cache node */ - node = (ozone_node_t*)file_list_get_userdata_at_offset(selection_buf, i); - - if (!node) - continue; - - node->height = (entry.sublabel ? 100 : 60-8); - node->wrap = false; - - if (entry.sublabel) - { - char *sublabel_str = menu_entry_get_sublabel(&entry); - - word_wrap(sublabel_str, sublabel_str, (video_info_width - 548) / ozone->sublabel_font_glyph_width, false); - - unsigned lines = ozone_count_lines(sublabel_str); - - if (lines > 1) - { - node->height += lines * 15; - node->wrap = true; - } - - free(sublabel_str); - } - - node->position_y = ozone->entries_height; - - ozone->entries_height += node->height; - - menu_entry_free(&entry); - } - - /* Update scrolling */ - ozone->selection = menu_navigation_get_selection(); - ozone_update_scroll(ozone, false, (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, ozone->selection)); -} - -static void ozone_render(void *data, bool is_idle) -{ - size_t i; - menu_animation_ctx_delta_t delta; - unsigned end = (unsigned)menu_entries_get_size(); - ozone_handle_t *ozone = (ozone_handle_t*)data; - if (!data) - return; - - if (ozone->need_compute) - { - ozone_compute_entries_position(ozone); - ozone->need_compute = false; - } - - ozone->selection = menu_navigation_get_selection(); - - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - menu_animation_update(delta.ideal); - - /* TODO Handle pointer & mouse */ - - menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); - - if (i >= end) - { - i = 0; - menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &i); - } - - menu_animation_ctl(MENU_ANIMATION_CTL_CLEAR_ACTIVE, NULL); -} - -static void ozone_draw_icon( - video_frame_info_t *video_info, - unsigned icon_width, - unsigned icon_height, - uintptr_t texture, - float x, float y, - unsigned width, unsigned height, - float rotation, float scale_factor, - float *color) -{ - menu_display_ctx_rotate_draw_t rotate_draw; - menu_display_ctx_draw_t draw; - struct video_coords coords; - math_matrix_4x4 mymat; - - rotate_draw.matrix = &mymat; - rotate_draw.rotation = rotation; - rotate_draw.scale_x = scale_factor; - rotate_draw.scale_y = scale_factor; - rotate_draw.scale_z = 1; - rotate_draw.scale_enable = true; - - menu_display_rotate_z(&rotate_draw, video_info); - - coords.vertices = 4; - coords.vertex = NULL; - coords.tex_coord = NULL; - coords.lut_tex_coord = NULL; - coords.color = color ? (const float*)color : ozone_pure_white; - - draw.x = x; - draw.y = height - y - icon_height; - draw.width = icon_width; - draw.height = icon_height; - draw.scale_factor = scale_factor; - draw.rotation = rotation; - draw.coords = &coords; - draw.matrix_data = &mymat; - draw.texture = texture; - draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP; - draw.pipeline.id = 0; - - menu_display_draw(&draw, video_info); -} - -static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_info) -{ - char title[255]; - menu_animation_ctx_ticker_t ticker; - settings_t *settings = config_get_ptr(); - unsigned timedate_offset = 0; - - /* Separator */ - menu_display_draw_quad(video_info, 30, 87, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); - - /* Title */ - ticker.s = title; - ticker.len = (video_info->width - 128 - 47 - 130) / ozone->title_font_glyph_width; - ticker.idx = ozone->frame_count / 20; - ticker.str = ozone->title; - ticker.selected = true; - - menu_animation_ticker(&ticker); - - ozone_draw_text(video_info, ozone, title, 128, 20 + FONT_SIZE_TITLE, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.title, ozone->theme->text_rgba, false); - - /* Icon */ - menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_RETROARCH], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); - menu_display_blend_end(video_info); - - /* Battery */ - if (video_info->battery_level_enable) - { - char msg[12]; - static retro_time_t last_time = 0; - bool charging = false; - retro_time_t current_time = cpu_features_get_time_usec(); - int percent = 0; - enum frontend_powerstate state = get_last_powerstate(&percent); - - if (state == FRONTEND_POWERSTATE_CHARGING) - charging = true; - - if (current_time - last_time >= INTERVAL_BATTERY_LEVEL_CHECK) - { - last_time = current_time; - task_push_get_powerstate(); - } - - *msg = '\0'; - - if (percent > 0) - { - timedate_offset = 95; - - snprintf(msg, sizeof(msg), "%d%%", percent); - - ozone_draw_text(video_info, ozone, msg, video_info->width - 85, 30 + FONT_SIZE_TIME, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba, false); - - menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[charging ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL], video_info->width - 60 - 56, 30 - 28, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); - menu_display_blend_end(video_info); - } - } - - /* Timedate */ - if (video_info->timedate_enable) - { - menu_display_ctx_datetime_t datetime; - char timedate[255]; - - timedate[0] = '\0'; - - datetime.s = timedate; - datetime.time_mode = settings->uints.menu_timedate_style; - datetime.len = sizeof(timedate); - - menu_display_timedate(&datetime); - - ozone_draw_text(video_info, ozone, timedate, video_info->width - 87 - timedate_offset, 30 + FONT_SIZE_TIME, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba, false); - - menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOCK], video_info->width - 60 - 56 - timedate_offset, 30 - 28, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); - menu_display_blend_end(video_info); - } -} - -static void ozone_color_alpha(float *color, float alpha) -{ - color[3] = color[7] = color[11] = color[15] = alpha; -} - -static void ozone_draw_footer(ozone_handle_t *ozone, video_frame_info_t *video_info, settings_t *settings) -{ - char core_title[255]; - /* Separator */ - menu_display_draw_quad(video_info, 23, video_info->height - 78, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); - - /* Core title or Switch icon */ - if (settings->bools.menu_core_enable && menu_entries_get_core_title(core_title, sizeof(core_title)) == 0) - ozone_draw_text(video_info, ozone, core_title, 59, video_info->height - 49 + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); - else - ozone_draw_icon(video_info, 69, 30, ozone->theme->textures[OZONE_THEME_TEXTURE_SWITCH], 59, video_info->height - 52, video_info->width,video_info->height, 0, 1, NULL); - - /* Buttons */ - - { - unsigned back_width = 215; - unsigned back_height = 49; - unsigned ok_width = 96; - unsigned ok_height = 49; - bool do_swap = video_info->input_menu_swap_ok_cancel_buttons; - - if (do_swap) - { - back_width = 96; - back_height = 49; - ok_width = 215; - ok_height = 49; - } - - menu_display_blend_begin(video_info); - - if (do_swap) - { - ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_B], video_info->width - 133, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); - ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_A], video_info->width - 251, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); - } - else - { - ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_B], video_info->width - 251, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); - ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_A], video_info->width - 133, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); - } - - menu_display_blend_end(video_info); - - ozone_draw_text(video_info, ozone, - do_swap ? - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_OK) : - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK), - video_info->width - back_width, video_info->height - back_height + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); - ozone_draw_text(video_info, ozone, - do_swap ? - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK) : - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_OK), - video_info->width - ok_width, video_info->height - ok_height + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); - } - - menu_display_blend_end(video_info); -} - -/* TODO Fluid sidebar width ? */ - -static void ozone_draw_cursor_slice(ozone_handle_t *ozone, - video_frame_info_t *video_info, - int x_offset, - unsigned width, unsigned height, - size_t y, float alpha) -{ - ozone_color_alpha(ozone->theme_dynamic.cursor_alpha, alpha); - ozone_color_alpha(ozone->theme_dynamic.cursor_border, alpha); - - menu_display_blend_begin(video_info); - - /* Cursor without border */ - menu_display_draw_texture_slice( - video_info, - x_offset - 14, - y + 8, - 80, 80, - width + 3 + 28 - 4, - height + 20, - video_info->width, video_info->height, - ozone->theme_dynamic.cursor_alpha, - 20, 1.0, - ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_NO_BORDER] - ); - - /* Tainted border */ - menu_display_draw_texture_slice( - video_info, - x_offset - 14, - y + 8, - 80, 80, - width + 3 + 28 - 4, - height + 20, - video_info->width, video_info->height, - ozone->theme_dynamic.cursor_border, - 20, 1.0, - ozone->textures[OZONE_TEXTURE_CURSOR_BORDER] - ); - - menu_display_blend_end(video_info); -} - -static void ozone_draw_cursor_fallback(ozone_handle_t *ozone, - video_frame_info_t *video_info, - int x_offset, - unsigned width, unsigned height, - size_t y, float alpha) -{ - ozone_color_alpha(ozone->theme_dynamic.selection_border, alpha); - ozone_color_alpha(ozone->theme_dynamic.selection, alpha); - - /* Fill */ - menu_display_draw_quad(video_info, x_offset, y, width, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection); - - /* Borders (can't do one single quad because of alpha) */ - - /* Top */ - menu_display_draw_quad(video_info, x_offset - 3, y - 3, width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); - - /* Bottom */ - menu_display_draw_quad(video_info, x_offset - 3, y + height - 5, width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); - - /* Left */ - menu_display_draw_quad(video_info, x_offset - 3, y, 3, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); - - /* Right */ - menu_display_draw_quad(video_info, x_offset + width, y, 3, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); -} - -static void ozone_draw_cursor(ozone_handle_t *ozone, - video_frame_info_t *video_info, - int x_offset, - unsigned width, unsigned height, - size_t y, float alpha) -{ - if (ozone->has_all_assets) - ozone_draw_cursor_slice(ozone, video_info, x_offset, width, height, y, alpha); - else - ozone_draw_cursor_fallback(ozone, video_info, x_offset, width, height, y, alpha); -} - -static void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info) -{ - size_t y; - unsigned i, sidebar_height; - char console_title[255]; - menu_animation_ctx_ticker_t ticker; - - unsigned selection_y = 0; - unsigned selection_old_y = 0; - unsigned horizontal_list_size = 0; - - if (!ozone->draw_sidebar) - return; - - if (ozone->horizontal_list) - horizontal_list_size = ozone->horizontal_list->size; - - menu_display_scissor_begin(video_info, 0, 87, 408, video_info->height - 87 - 78); - - /* Background */ - sidebar_height = video_info->height - 87 - 55 - 78; - - if (!video_info->libretro_running) - { - menu_display_draw_quad(video_info, ozone->sidebar_offset, 88, 408, 55/2, video_info->width, video_info->height, ozone->theme->sidebar_top_gradient); - menu_display_draw_quad(video_info, ozone->sidebar_offset, 88 + 55/2, 408, sidebar_height, video_info->width, video_info->height, ozone->theme->sidebar_background); - menu_display_draw_quad(video_info, ozone->sidebar_offset, 55*2 + sidebar_height, 408, 55/2 + 1, video_info->width, video_info->height, ozone->theme->sidebar_bottom_gradient); - } - - /* Tabs */ - /* y offset computation */ - y = ENTRIES_START_Y - 10; - for (i = 0; i < ozone->system_tab_end + horizontal_list_size + 1; i++) - { - if (i == ozone->categories_selection_ptr) - { - selection_y = y; - if (ozone->categories_selection_ptr > ozone->system_tab_end) - selection_y += 30; - } - - if (i == ozone->categories_active_idx_old) - { - selection_old_y = y; - if (ozone->categories_active_idx_old > ozone->system_tab_end) - selection_old_y += 30; - } - - y += 65; - } - - /* Cursor */ - if (ozone->cursor_in_sidebar) - ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408 - 81, 52, selection_y-8 + ozone->animations.scroll_y_sidebar, ozone->animations.cursor_alpha); - - if (ozone->cursor_in_sidebar_old) - ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408 - 81, 52, selection_old_y-8 + ozone->animations.scroll_y_sidebar, 1-ozone->animations.cursor_alpha); - - /* Menu tabs */ - y = ENTRIES_START_Y - 10; - menu_display_blend_begin(video_info); - - for (i = 0; i < ozone->system_tab_end+1; i++) - { - enum msg_hash_enums value_idx; - const char *title = NULL; - bool selected = (ozone->categories_selection_ptr == i); - unsigned icon = ozone_system_tabs_icons[ozone->tabs[i]]; - - /* Icon */ - ozone_draw_icon(video_info, 40, 40, ozone->tab_textures[icon], ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); - - value_idx = ozone_system_tabs_value[ozone->tabs[i]]; - title = msg_hash_to_str(value_idx); - - /* Text */ - ozone_draw_text(video_info, ozone, title, ozone->sidebar_offset + 115 - 10, y + FONT_SIZE_SIDEBAR + ozone->animations.scroll_y_sidebar, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.sidebar, (selected ? ozone->theme->text_selected_rgba : ozone->theme->text_rgba), true); - - y += 65; - } - - menu_display_blend_end(video_info); - - /* Console tabs */ - if (horizontal_list_size > 0) - { - menu_display_draw_quad(video_info, ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, 408-81, 1, video_info->width, video_info->height, ozone->theme->entries_border); - - y += 30; - - menu_display_blend_begin(video_info); - - for (i = 0; i < horizontal_list_size; i++) - { - bool selected = (ozone->categories_selection_ptr == ozone->system_tab_end + 1 + i); - - ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, i); - - if (!node) - goto console_iterate; - - /* Icon */ - ozone_draw_icon(video_info, 40, 40, node->icon, ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); - - /* Text */ - ticker.idx = ozone->frame_count / 20; - ticker.len = 19; - ticker.s = console_title; - ticker.selected = selected; - ticker.str = node->console_name; - - menu_animation_ticker(&ticker); - - ozone_draw_text(video_info, ozone, console_title, ozone->sidebar_offset + 115 - 10, y + FONT_SIZE_SIDEBAR + ozone->animations.scroll_y_sidebar, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.sidebar, (selected ? ozone->theme->text_selected_rgba : ozone->theme->text_rgba), true); - -console_iterate: - y += 65; - } - - menu_display_blend_end(video_info); - - } - - font_driver_flush(video_info->width, video_info->height, ozone->fonts.sidebar, video_info); - ozone->raster_blocks.sidebar.carr.coords.vertices = 0; - - menu_display_scissor_end(video_info); -} - -static void ozone_draw_entry_value(ozone_handle_t *ozone, - video_frame_info_t *video_info, - char *value, - unsigned x, unsigned y, - uint32_t alpha_uint32, - menu_entry_t *entry) -{ - bool switch_is_on = true; - bool do_draw_text = false; - - if (!entry->checked && string_is_empty(value)) - return; - - /* check icon */ - if (entry->checked) - { - menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 30, 30, ozone->theme->textures[OZONE_THEME_TEXTURE_CHECK], x - 20, y - 22, video_info->width, video_info->height, 0, 1, ozone->theme_dynamic.entries_checkmark); - menu_display_blend_end(video_info); - return; - } - - /* text value */ - if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || - (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))) - { - switch_is_on = false; - do_draw_text = false; - } - else if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || - (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)))) - { - switch_is_on = true; - do_draw_text = false; - } - else - { - if (!string_is_empty(entry->value)) - { - if ( - string_is_equal(entry->value, "...") || - string_is_equal(entry->value, "(PRESET)") || - string_is_equal(entry->value, "(SHADER)") || - string_is_equal(entry->value, "(COMP)") || - string_is_equal(entry->value, "(CORE)") || - string_is_equal(entry->value, "(MOVIE)") || - string_is_equal(entry->value, "(MUSIC)") || - string_is_equal(entry->value, "(DIR)") || - string_is_equal(entry->value, "(RDB)") || - string_is_equal(entry->value, "(CURSOR)")|| - string_is_equal(entry->value, "(CFILE)") || - string_is_equal(entry->value, "(FILE)") || - string_is_equal(entry->value, "(IMAGE)") - ) - { - return; - } - else - do_draw_text = true; - } - else - do_draw_text = true; - } - - if (do_draw_text) - { - ozone_draw_text(video_info, ozone, value, x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, COLOR_TEXT_ALPHA(ozone->theme->text_selected_rgba, alpha_uint32), false); - } - else - { - ozone_draw_text(video_info, ozone, (switch_is_on ? msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON) : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)), - x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, - COLOR_TEXT_ALPHA(switch_is_on ? ozone->theme->text_selected_rgba : ozone->theme->text_sublabel_rgba, alpha_uint32), false); - } -} - -static void ozone_draw_entries(ozone_handle_t *ozone, video_frame_info_t *video_info, - unsigned selection, unsigned selection_old, - file_list_t *selection_buf, float alpha, float scroll_y, - bool is_playlist) -{ - bool old_list; - uint32_t alpha_uint32; - size_t i, y, entries_end; - float sidebar_offset, bottom_boundary, invert, alpha_anim; - unsigned video_info_height, video_info_width, entry_width, button_height; - menu_entry_t entry; - int x_offset = 22; - size_t selection_y = 0; - size_t old_selection_y = 0; - - menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); - - entries_end = file_list_get_size(selection_buf); - old_list = selection_buf == ozone->selection_buf_old; - y = ENTRIES_START_Y; - sidebar_offset = ozone->sidebar_offset / 2.0f; - entry_width = video_info->width - 548; - button_height = 52; /* height of the button (entry minus sublabel) */ - - video_driver_get_size(&video_info_width, &video_info_height); - - bottom_boundary = video_info_height - 87 - 78; - invert = (ozone->fade_direction) ? -1 : 1; - alpha_anim = old_list ? alpha : 1.0f - alpha; - - if (old_list) - alpha = 1.0f - alpha; - - if (alpha != 1.0f) - { - if (old_list) - x_offset += invert * -(alpha_anim * 120); /* left */ - else - x_offset += invert * (alpha_anim * 120); /* right */ - } - - x_offset += (int) sidebar_offset; - alpha_uint32 = (uint32_t)(alpha*255.0f); - - /* Borders layer */ - for (i = 0; i < entries_end; i++) - { - bool entry_selected = selection == i; - bool entry_old_selected = selection_old == i; - ozone_node_t *node = NULL; - if (entry_selected) - selection_y = y; - - if (entry_old_selected) - old_selection_y = y; - - node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); - - if (!node || ozone->empty_playlist) - goto border_iterate; - - if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) - goto border_iterate; - else if (y + scroll_y - node->height - 20 > bottom_boundary) - goto border_iterate; - - ozone_color_alpha(ozone->theme_dynamic.entries_border, alpha); - ozone_color_alpha(ozone->theme_dynamic.entries_checkmark, alpha); - - /* Borders */ - menu_display_draw_quad(video_info, x_offset + 456-3, y - 3 + scroll_y, entry_width + 10 - 3 -1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); - menu_display_draw_quad(video_info, x_offset + 456-3, y - 3 + button_height + scroll_y, entry_width + 10 - 3-1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); - -border_iterate: - y += node->height; - } - - /* Cursor(s) layer - current */ - if (!ozone->cursor_in_sidebar) - ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, button_height, selection_y + scroll_y, ozone->animations.cursor_alpha * alpha); - - /* Old*/ - if (!ozone->cursor_in_sidebar_old) - ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, button_height, old_selection_y + scroll_y, (1-ozone->animations.cursor_alpha) * alpha); - - /* Icons + text */ - y = ENTRIES_START_Y; - - if (old_list) - y += ozone->old_list_offset_y; - - for (i = 0; i < entries_end; i++) - { - unsigned icon; - menu_entry_t entry; - menu_animation_ctx_ticker_t ticker; - char entry_value[255]; - char rich_label[255]; - char entry_value_ticker[255]; - char *sublabel_str; - ozone_node_t *node = NULL; - char *entry_rich_label = NULL; - bool entry_selected = false; - int text_offset = -40; - - entry_value[0] = '\0'; - entry_selected = selection == i; - node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); - - menu_entry_init(&entry); - menu_entry_get(&entry, 0, (unsigned)i, selection_buf, true); - menu_entry_get_value(&entry, entry_value, sizeof(entry_value)); - - if (!node) - continue; - - if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) - goto icons_iterate; - else if (y + scroll_y - node->height - 20 > bottom_boundary) - goto icons_iterate; - - /* Prepare text */ - entry_rich_label = menu_entry_get_rich_label(&entry); - - ticker.idx = ozone->frame_count / 20; - ticker.s = rich_label; - ticker.str = entry_rich_label; - ticker.selected = entry_selected && !ozone->cursor_in_sidebar; - ticker.len = (entry_width - 60 - text_offset) / ozone->entry_font_glyph_width; - - menu_animation_ticker(&ticker); - - if (ozone->empty_playlist) - { - unsigned text_width = font_driver_get_message_width(ozone->fonts.entries_label, rich_label, (unsigned)strlen(rich_label), 1); - x_offset = (video_info_width - 408 - 162)/2 - text_width/2; - y = video_info_height/2 - 60; - } - - sublabel_str = menu_entry_get_sublabel(&entry); - - if (node->wrap) - word_wrap(sublabel_str, sublabel_str, (video_info->width - 548) / ozone->sublabel_font_glyph_width, false); - - /* Icon */ - icon = ozone_entries_icon_get_id(ozone, entry.enum_idx, entry.type, entry_selected); - if (icon != OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING) - { - uintptr_t texture = ozone->icons_textures[icon]; - - /* Console specific icons */ - if (entry.type == FILE_TYPE_RPL_ENTRY && ozone->horizontal_list && ozone->categories_selection_ptr > ozone->system_tab_end) - { - ozone_node_t *sidebar_node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, ozone->categories_selection_ptr - ozone->system_tab_end-1); - - if (!sidebar_node || !sidebar_node->content_icon) - texture = ozone->icons_textures[icon]; - else - texture = sidebar_node->content_icon; - } - - ozone_color_alpha(ozone->theme_dynamic.entries_icon, alpha); - - menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 46, 46, texture, x_offset + 451+5+10, y + scroll_y, video_info->width, video_info->height, 0, 1, ozone->theme_dynamic.entries_icon); - menu_display_blend_end(video_info); - - text_offset = 0; - } - - /* Draw text */ - ozone_draw_text(video_info, ozone, rich_label, text_offset + x_offset + 521, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, COLOR_TEXT_ALPHA(ozone->theme->text_rgba, alpha_uint32), false); - ozone_draw_text(video_info, ozone, sublabel_str, x_offset + 470, y + FONT_SIZE_ENTRIES_SUBLABEL + 80 - 20 - 3 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_sublabel, COLOR_TEXT_ALPHA(ozone->theme->text_sublabel_rgba, alpha_uint32), false); - - /* Value */ - ticker.idx = ozone->frame_count / 20; - ticker.s = entry_value_ticker; - ticker.str = entry_value; - ticker.selected = entry_selected && !ozone->cursor_in_sidebar; - ticker.len = (entry_width - 60 - ((int)utf8len(entry_rich_label) * ozone->entry_font_glyph_width)) / ozone->entry_font_glyph_width; - - menu_animation_ticker(&ticker); - ozone_draw_entry_value(ozone, video_info, entry_value_ticker, x_offset + 426 + entry_width, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y,alpha_uint32, &entry); - - free(entry_rich_label); - free(sublabel_str); - -icons_iterate: - y += node->height; - menu_entry_free(&entry); - } - - /* Text layer */ - font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_label, video_info); - font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_sublabel, video_info); -} - -static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_animation_ctx_tag tag = (uintptr_t) selection_buf; - - size_t new_selection = menu_navigation_get_selection(); - ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, new_selection); - - if (!node) - return; - - if (ozone->selection != new_selection) - { - ozone->selection_old = ozone->selection; - ozone->selection = new_selection; - - ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; - - menu_animation_kill_by_tag(&tag); - - ozone_update_scroll(ozone, allow_animation, node); - } -} - -static void ozone_navigation_clear(void *data, bool pending_push) -{ - ozone_handle_t *ozone = (ozone_handle_t*)data; - if (!pending_push) - ozone_selection_changed(ozone, true); -} - -static void ozone_navigation_pointer_changed(void *data) -{ - ozone_handle_t *ozone = (ozone_handle_t*)data; - ozone_selection_changed(ozone, true); -} - -static void ozone_navigation_set(void *data, bool scroll) -{ - ozone_handle_t *ozone = (ozone_handle_t*)data; - ozone_selection_changed(ozone, true); -} - -static void ozone_navigation_alphabet(void *data, size_t *unused) -{ - ozone_handle_t *ozone = (ozone_handle_t*)data; - ozone_selection_changed(ozone, true); -} - -static unsigned ozone_get_system_theme() -{ - unsigned ret = 0; -#ifdef HAVE_LIBNX - if (R_SUCCEEDED(setsysInitialize())) - { - ColorSetId theme; - setsysGetColorSetId(&theme); - ret = (theme == ColorSetId_Dark) ? 1 : 0; - setsysExit(); - } - - return ret; -#endif - return 0; -} - -static void ozone_draw_backdrop(video_frame_info_t *video_info, float alpha) -{ - /* TODO Replace this backdrop by a blur shader on the whole screen if available */ - if (alpha == -1) - alpha = 0.75f; - ozone_color_alpha(ozone_backdrop, alpha); - menu_display_draw_quad(video_info, 0, 0, video_info->width, video_info->height, video_info->width, video_info->height, ozone_backdrop); -} - -static void ozone_draw_osk(ozone_handle_t *ozone, - video_frame_info_t *video_info, - const char *label, const char *str) -{ - int i; - const char *text; - char message[2048]; - unsigned text_color; - struct string_list *list; - - unsigned margin = 75; - unsigned padding = 10; - unsigned bottom_end = video_info->height/2; - unsigned y_offset = 0; - bool draw_placeholder = string_is_empty(str); - - retro_time_t current_time = cpu_features_get_time_usec(); - static retro_time_t last_time = 0; - - if (current_time - last_time >= INTERVAL_OSK_CURSOR) - { - ozone->osk_cursor = !ozone->osk_cursor; - last_time = current_time; - } - - /* Border */ - /* Top */ - menu_display_draw_quad(video_info, margin, margin, video_info->width - margin*2, 1, video_info->width, video_info->height, ozone->theme->entries_border); - - /* Bottom */ - menu_display_draw_quad(video_info, margin, bottom_end - margin, video_info->width - margin*2, 1, video_info->width, video_info->height, ozone->theme->entries_border); - - /* Left */ - menu_display_draw_quad(video_info, margin, margin, 1, bottom_end - margin*2, video_info->width, video_info->height, ozone->theme->entries_border); - - /* Right */ - menu_display_draw_quad(video_info, video_info->width - margin, margin, 1, bottom_end - margin*2, video_info->width, video_info->height, ozone->theme->entries_border); - - /* Backdrop */ - /* TODO Remove the backdrop if blur shader is available */ - menu_display_draw_quad(video_info, margin + 1, margin + 1, video_info->width - margin*2 - 2, bottom_end - margin*2 - 2, video_info->width, video_info->height, ozone_osk_backdrop); - - /* Placeholder & text*/ - if (!draw_placeholder) - { - text = str; - text_color = 0xffffffff; - } - else - { - text = label; - text_color = ozone_theme_light.text_sublabel_rgba; - } - - word_wrap(message, text, (video_info->width - margin*2 - padding*2) / ozone->entry_font_glyph_width, true); - - list = string_split(message, "\n"); - - for (i = 0; i < list->size; i++) - { - const char *msg = list->elems[i].data; - - ozone_draw_text(video_info, ozone, msg, margin + padding * 2, margin + padding + FONT_SIZE_ENTRIES_LABEL + y_offset, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, text_color, false); - - /* Cursor */ - if (i == list->size - 1) - { - if (ozone->osk_cursor) - { - unsigned cursor_x = draw_placeholder ? 0 : font_driver_get_message_width(ozone->fonts.entries_label, msg, (unsigned)strlen(msg), 1); - menu_display_draw_quad(video_info, margin + padding*2 + cursor_x, margin + padding + y_offset + 3, 1, 25, video_info->width, video_info->height, ozone_pure_white); - } - } - else - { - y_offset += 25; - } - } - - /* Keyboard */ - menu_display_draw_keyboard( - ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_STATIC], - ozone->fonts.entries_label, - video_info, - menu_event_get_osk_grid(), - menu_event_get_osk_ptr(), - ozone->theme->text_rgba); - - string_list_free(list); -} - -static void ozone_draw_messagebox(ozone_handle_t *ozone, - video_frame_info_t *video_info, - const char *message) -{ - unsigned i, y_position; - int x, y, longest = 0, longest_width = 0; - float line_height = 0; - unsigned width = video_info->width; - unsigned height = video_info->height; - struct string_list *list = !string_is_empty(message) - ? string_split(message, "\n") : NULL; - - if (!list || !ozone || !ozone->fonts.footer) - { - if (list) - string_list_free(list); - return; - } - - if (list->elems == 0) - goto end; - - line_height = 25; - - y_position = height / 2; - if (menu_input_dialog_get_display_kb()) - y_position = height / 4; - - x = width / 2; - y = y_position - (list->size-1) * line_height / 2; - - /* find the longest line width */ - for (i = 0; i < list->size; i++) - { - const char *msg = list->elems[i].data; - int len = (int)utf8len(msg); - - if (len > longest) - { - longest = len; - longest_width = font_driver_get_message_width( - ozone->fonts.footer, msg, (unsigned)strlen(msg), 1); - } - } - - ozone_color_alpha(ozone->theme_dynamic.message_background, ozone->animations.messagebox_alpha); - - menu_display_blend_begin(video_info); - - if (ozone->has_all_assets) /* avoid drawing a black box if there's no assets */ - menu_display_draw_texture_slice( - video_info, - x - longest_width/2 - 48, - y + 16 - 48, - 256, 256, - longest_width + 48 * 2, - line_height * list->size + 48 * 2, - width, height, - ozone->theme_dynamic.message_background, - 16, 1.0, - ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE] - ); - - for (i = 0; i < list->size; i++) - { - const char *msg = list->elems[i].data; - - if (msg) - ozone_draw_text(video_info, ozone, - msg, - x - longest_width/2.0, - y + (i+0.75) * line_height, - TEXT_ALIGN_LEFT, - width, height, - ozone->fonts.footer, - COLOR_TEXT_ALPHA(ozone->theme->text_rgba, (uint32_t)(ozone->animations.messagebox_alpha*255.0f)), - false - ); - } - -end: - string_list_free(list); -} - -static void ozone_messagebox_fadeout_cb(void *userdata) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - - free(ozone->pending_message); - ozone->pending_message = NULL; - - ozone->should_draw_messagebox = false; -} - -static void ozone_frame(void *data, video_frame_info_t *video_info) -{ - ozone_handle_t* ozone = (ozone_handle_t*) data; - settings_t *settings = config_get_ptr(); - unsigned color_theme = video_info->ozone_color_theme; - menu_animation_ctx_tag messagebox_tag = (uintptr_t)ozone->pending_message; - - menu_animation_ctx_entry_t entry; - - if (!ozone) - return; - - /* Change theme on the fly */ - if (color_theme != last_color_theme || last_use_preferred_system_color_theme != settings->bools.menu_use_preferred_system_color_theme) - { - if (!settings->bools.menu_use_preferred_system_color_theme) - ozone_set_color_theme(ozone, color_theme); - else - { - video_info->ozone_color_theme = ozone_get_system_theme(); - ozone_set_color_theme(ozone, video_info->ozone_color_theme); - } - - last_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme; - } - - ozone->frame_count++; - - menu_display_set_viewport(video_info->width, video_info->height); - - /* Clear text */ - font_driver_bind_block(ozone->fonts.footer, &ozone->raster_blocks.footer); - font_driver_bind_block(ozone->fonts.title, &ozone->raster_blocks.title); - font_driver_bind_block(ozone->fonts.time, &ozone->raster_blocks.time); - font_driver_bind_block(ozone->fonts.entries_label, &ozone->raster_blocks.entries_label); - font_driver_bind_block(ozone->fonts.entries_sublabel, &ozone->raster_blocks.entries_sublabel); - font_driver_bind_block(ozone->fonts.sidebar, &ozone->raster_blocks.sidebar); - - ozone->raster_blocks.footer.carr.coords.vertices = 0; - ozone->raster_blocks.title.carr.coords.vertices = 0; - ozone->raster_blocks.time.carr.coords.vertices = 0; - ozone->raster_blocks.entries_label.carr.coords.vertices = 0; - ozone->raster_blocks.entries_sublabel.carr.coords.vertices = 0; - ozone->raster_blocks.sidebar.carr.coords.vertices = 0; - - /* TODO Replace this by blur backdrop if available */ - ozone_color_alpha(ozone->theme->background, video_info->libretro_running ? 0.75f : 1.0f); - - /* Background */ - menu_display_draw_quad(video_info, - 0, 0, video_info->width, video_info->height, - video_info->width, video_info->height, - ozone->theme->background - ); - - /* Header, footer */ - ozone_draw_header(ozone, video_info); - ozone_draw_footer(ozone, video_info, settings); - - /* Sidebar */ - ozone_draw_sidebar(ozone, video_info); - - /* Menu entries */ - menu_display_scissor_begin(video_info, ozone->sidebar_offset + 408, 87, video_info->width - 408 + (-ozone->sidebar_offset), video_info->height - 87 - 78); - - /* Current list */ - ozone_draw_entries(ozone, - video_info, - ozone->selection, - ozone->selection_old, - menu_entries_get_selection_buf_ptr(0), - ozone->animations.list_alpha, - ozone->animations.scroll_y, - ozone->is_playlist - ); - - /* Old list */ - if (ozone->draw_old_list) - ozone_draw_entries(ozone, - video_info, - ozone->selection_old_list, - ozone->selection_old_list, - ozone->selection_buf_old, - ozone->animations.list_alpha, - ozone->scroll_old, - ozone->is_playlist_old - ); - - menu_display_scissor_end(video_info); - - /* Flush first layer of text */ - font_driver_flush(video_info->width, video_info->height, ozone->fonts.footer, video_info); - font_driver_flush(video_info->width, video_info->height, ozone->fonts.title, video_info); - font_driver_flush(video_info->width, video_info->height, ozone->fonts.time, video_info); - - font_driver_bind_block(ozone->fonts.footer, NULL); - font_driver_bind_block(ozone->fonts.title, NULL); - font_driver_bind_block(ozone->fonts.time, NULL); - font_driver_bind_block(ozone->fonts.entries_label, NULL); - - /* Message box & OSK - second layer of text */ - ozone->raster_blocks.footer.carr.coords.vertices = 0; - ozone->raster_blocks.entries_label.carr.coords.vertices = 0; - - if (ozone->should_draw_messagebox || menu_input_dialog_get_display_kb()) - { - /* Fade in animation */ - if (ozone->messagebox_state_old != ozone->messagebox_state && ozone->messagebox_state) - { - ozone->messagebox_state_old = ozone->messagebox_state; - - menu_animation_kill_by_tag(&messagebox_tag); - ozone->animations.messagebox_alpha = 0.0f; - - entry.cb = NULL; - entry.duration = ANIMATION_PUSH_ENTRY_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.messagebox_alpha; - entry.tag = messagebox_tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); - } - /* Fade out animation */ - else if (ozone->messagebox_state_old != ozone->messagebox_state && !ozone->messagebox_state) - { - ozone->messagebox_state_old = ozone->messagebox_state; - ozone->messagebox_state = false; - - menu_animation_kill_by_tag(&messagebox_tag); - ozone->animations.messagebox_alpha = 1.0f; - - entry.cb = ozone_messagebox_fadeout_cb; - entry.duration = ANIMATION_PUSH_ENTRY_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.messagebox_alpha; - entry.tag = messagebox_tag; - entry.target_value = 0.0f; - entry.userdata = ozone; - - menu_animation_push(&entry); - } - - ozone_draw_backdrop(video_info, fmin(ozone->animations.messagebox_alpha, 0.75f)); - - if (menu_input_dialog_get_display_kb()) - { - const char *label = menu_input_dialog_get_label_buffer(); - const char *str = menu_input_dialog_get_buffer(); - - ozone_draw_osk(ozone, video_info, label, str); - } - else - { - ozone_draw_messagebox(ozone, video_info, ozone->pending_message); - } - } - - font_driver_flush(video_info->width, video_info->height, ozone->fonts.footer, video_info); - font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_label, video_info); - - menu_display_unset_viewport(video_info->width, video_info->height); -} - -static void ozone_set_header(ozone_handle_t *ozone) -{ - if (ozone->categories_selection_ptr <= ozone->system_tab_end) - { - menu_entries_get_title(ozone->title, sizeof(ozone->title)); - } - else if (ozone->horizontal_list) - { - ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, ozone->categories_selection_ptr - ozone->system_tab_end-1); - - if (node && node->console_name) - strlcpy(ozone->title, node->console_name, sizeof(ozone->title)); - } -} - -static void ozone_animation_end(void *userdata) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - ozone->draw_old_list = false; -} - -static void ozone_list_open(ozone_handle_t *ozone) -{ - struct menu_animation_ctx_entry entry; - - ozone->draw_old_list = true; - - /* Left/right animation */ - ozone->animations.list_alpha = 0.0f; - - entry.cb = ozone_animation_end; - entry.duration = ANIMATION_PUSH_ENTRY_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.list_alpha; - entry.tag = (uintptr_t) NULL; - entry.target_value = 1.0f; - entry.userdata = ozone; - - menu_animation_push(&entry); - - /* Sidebar animation */ - if (ozone->depth == 1) - { - ozone->draw_sidebar = true; - - entry.cb = NULL; - entry.duration = ANIMATION_PUSH_ENTRY_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->sidebar_offset; - entry.tag = (uintptr_t) NULL; - entry.target_value = 0.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); - } - else if (ozone->depth > 1) - { - struct menu_animation_ctx_entry entry; - - entry.cb = ozone_collapse_end; - entry.duration = ANIMATION_PUSH_ENTRY_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->sidebar_offset; - entry.tag = (uintptr_t) NULL; - entry.target_value = -408.0f; - entry.userdata = (void*) ozone; - - menu_animation_push(&entry); - } -} - -static void ozone_populate_entries(void *data, const char *path, const char *label, unsigned k) -{ - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (!ozone) - return; - - ozone_set_header(ozone); - - if (menu_driver_ctl(RARCH_MENU_CTL_IS_PREVENT_POPULATE, NULL)) - { - menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); - - /* TODO Update thumbnails */ - ozone_selection_changed(ozone, false); - return; - } - - ozone->need_compute = true; - - int new_depth = (int)ozone_list_get_size(ozone, MENU_LIST_PLAIN); - - ozone->fade_direction = new_depth <= ozone->depth; - ozone->depth = new_depth; - ozone->is_playlist = ozone_is_playlist(ozone); - - if (ozone->categories_selection_ptr == ozone->categories_active_idx_old) - { - ozone_list_open(ozone); - } -} - -static void ozone_change_tab(ozone_handle_t *ozone, - enum msg_hash_enums tab, - enum menu_settings_type type) -{ - file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); - size_t stack_size; - menu_ctx_list_t list_info; - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - size_t selection = menu_navigation_get_selection(); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)file_list_get_actiondata_at_offset(selection_buf, - selection) : NULL; - - list_info.type = MENU_LIST_HORIZONTAL; - list_info.action = MENU_ACTION_LEFT; - - stack_size = menu_stack->size; - - if (menu_stack->list[stack_size - 1].label) - free(menu_stack->list[stack_size - 1].label); - menu_stack->list[stack_size - 1].label = NULL; - - menu_stack->list[stack_size - 1].label = - strdup(msg_hash_to_str(tab)); - menu_stack->list[stack_size - 1].type = - type; - - menu_driver_list_cache(&list_info); - - if (cbs && cbs->action_content_list_switch) - cbs->action_content_list_switch(selection_buf, menu_stack, "", "", 0); -} - -static void ozone_go_to_sidebar(ozone_handle_t *ozone, uintptr_t tag) -{ - struct menu_animation_ctx_entry entry; - - ozone->selection_old = ozone->selection; - ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; - ozone->cursor_in_sidebar = true; - - /* Cursor animation */ - ozone->animations.cursor_alpha = 0.0f; - - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.cursor_alpha; - entry.tag = tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); -} - -static void ozone_leave_sidebar(ozone_handle_t *ozone, uintptr_t tag) -{ - struct menu_animation_ctx_entry entry; - - if (ozone->empty_playlist) - return; - - ozone->categories_active_idx_old = ozone->categories_selection_ptr; - ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; - ozone->cursor_in_sidebar = false; - - /* Cursor animation */ - ozone->animations.cursor_alpha = 0.0f; - - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.cursor_alpha; - entry.tag = tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); -} - -static unsigned ozone_get_selected_sidebar_y_position(ozone_handle_t *ozone) -{ - return ozone->categories_selection_ptr * 65 + (ozone->categories_selection_ptr > ozone->system_tab_end ? 30 : 0); -} - -static unsigned ozone_get_sidebar_height(ozone_handle_t *ozone) -{ - return (ozone->system_tab_end + 1 + (ozone->horizontal_list ? ozone->horizontal_list->size : 0)) * 65 - + (ozone->horizontal_list && ozone->horizontal_list->size > 0 ? 30 : 0); -} - -static void ozone_sidebar_goto(ozone_handle_t *ozone, unsigned new_selection) -{ - unsigned video_info_height; - - video_driver_get_size(NULL, &video_info_height); - - struct menu_animation_ctx_entry entry; - - menu_animation_ctx_tag tag = (uintptr_t)ozone; - - if (ozone->categories_selection_ptr != new_selection) - { - ozone->categories_active_idx_old = ozone->categories_selection_ptr; - ozone->categories_selection_ptr = new_selection; - - ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; - - menu_animation_kill_by_tag(&tag); - } - - /* Cursor animation */ - ozone->animations.cursor_alpha = 0.0f; - - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.cursor_alpha; - entry.tag = tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - menu_animation_push(&entry); - - /* Scroll animation */ - float new_scroll = 0; - float selected_position_y = ozone_get_selected_sidebar_y_position(ozone); - float current_selection_middle_onscreen = ENTRIES_START_Y - 10 + ozone->animations.scroll_y_sidebar + selected_position_y + 65 / 2; - float bottom_boundary = video_info_height - 87 - 78; - float entries_middle = video_info_height/2; - float entries_height = ozone_get_sidebar_height(ozone); - - if (current_selection_middle_onscreen != entries_middle) - new_scroll = ozone->animations.scroll_y_sidebar - (current_selection_middle_onscreen - entries_middle); - - if (new_scroll + entries_height < bottom_boundary) - new_scroll = -(30 + entries_height - bottom_boundary); - - if (new_scroll > 0) - new_scroll = 0; - - entry.cb = NULL; - entry.duration = ANIMATION_CURSOR_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &ozone->animations.scroll_y_sidebar; - entry.tag = tag; - entry.target_value = new_scroll; - entry.userdata = NULL; - - menu_animation_push(&entry); - - if (new_selection > ozone->system_tab_end) - { - ozone_change_tab(ozone, MENU_ENUM_LABEL_HORIZONTAL_MENU, MENU_SETTING_HORIZONTAL_MENU); - } - else - { - ozone_change_tab(ozone, ozone_system_tabs_idx[ozone->tabs[new_selection]], ozone_system_tabs_type[ozone->tabs[new_selection]]); - } -} - -static int ozone_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_action action) -{ - int new_selection; - struct menu_animation_ctx_entry entry; - enum menu_action new_action; - menu_animation_ctx_tag tag; - - file_list_t *selection_buf = NULL; - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - unsigned horizontal_list_size = 0; - - if (ozone->horizontal_list) - horizontal_list_size = ozone->horizontal_list->size; - - ozone->messagebox_state = false || menu_input_dialog_get_display_kb(); - - if (!ozone) - return generic_menu_iterate(menu, userdata, action); - - selection_buf = menu_entries_get_selection_buf_ptr(0); - tag = (uintptr_t)selection_buf; - new_action = action; - - /* Inputs override */ - switch (action) - { - case MENU_ACTION_DOWN: - if (!ozone->cursor_in_sidebar) - break; - - tag = (uintptr_t)ozone; - - new_selection = (ozone->categories_selection_ptr + 1); - - if (new_selection >= ozone->system_tab_end + horizontal_list_size + 1) - new_selection = 0; - - ozone_sidebar_goto(ozone, new_selection); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_UP: - if (!ozone->cursor_in_sidebar) - break; - - tag = (uintptr_t)ozone; - - new_selection = ozone->categories_selection_ptr - 1; - - if (new_selection < 0) - new_selection = horizontal_list_size + ozone->system_tab_end; - - ozone_sidebar_goto(ozone, new_selection); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_LEFT: - if (ozone->cursor_in_sidebar) - { - new_action = MENU_ACTION_NOOP; - break; - } - else if (ozone->depth > 1) - break; - - ozone_go_to_sidebar(ozone, tag); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_RIGHT: - if (!ozone->cursor_in_sidebar) - { - if (ozone->depth == 1) - new_action = MENU_ACTION_NOOP; - break; - } - - ozone_leave_sidebar(ozone, tag); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_OK: - if (ozone->cursor_in_sidebar) - { - ozone_leave_sidebar(ozone, tag); - new_action = MENU_ACTION_NOOP; - break; - } - - break; - case MENU_ACTION_CANCEL: - if (ozone->cursor_in_sidebar) - { - /* Go back to main menu tab */ - if (ozone->categories_selection_ptr != 0) - ozone_sidebar_goto(ozone, 0); - - new_action = MENU_ACTION_NOOP; - break; - } - - if (menu_entries_get_stack_size(0) == 1) - { - ozone_go_to_sidebar(ozone, tag); - new_action = MENU_ACTION_NOOP; - } - break; - default: - break; - } - - return generic_menu_iterate(menu, userdata, new_action); -} - -/* TODO Fancy toggle animation */ - -static void ozone_toggle(void *userdata, bool menu_on) -{ - bool tmp = false; - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - - if (!ozone) - return; - - tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL); - - if (tmp) - menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); - else - menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); - - if (ozone->depth == 1) - { - ozone->draw_sidebar = true; - ozone->sidebar_offset = 0.0f; - } -} - -static bool ozone_menu_init_list(void *data) -{ - menu_displaylist_info_t info; - - file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - - menu_displaylist_info_init(&info); - - info.label = strdup( - msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)); - info.exts = - strdup(file_path_str(FILE_PATH_LPL_EXTENSION_NO_DOT)); - info.type_default = FILE_TYPE_PLAIN; - info.enum_idx = MENU_ENUM_LABEL_MAIN_MENU; - - menu_entries_append_enum(menu_stack, info.path, - info.label, - MENU_ENUM_LABEL_MAIN_MENU, - info.type, info.flags, 0); - - info.list = selection_buf; - - if (!menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info)) - goto error; - - info.need_push = true; - - if (!menu_displaylist_process(&info)) - goto error; - - menu_displaylist_info_free(&info); - return true; - -error: - menu_displaylist_info_free(&info); - return false; -} - -static ozone_node_t *ozone_copy_node(const ozone_node_t *old_node) -{ - ozone_node_t *new_node = (ozone_node_t*)malloc(sizeof(*new_node)); - - *new_node = *old_node; - - return new_node; -} - -static void ozone_list_insert(void *userdata, - file_list_t *list, - const char *path, - const char *fullpath, - const char *label, - size_t list_size, - unsigned type) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - ozone_node_t *node = NULL; - int i = (int)list_size; - - if (!ozone || !list) - return; - - ozone->need_compute = true; - - node = (ozone_node_t*)file_list_get_userdata_at_offset(list, i); - - if (!node) - node = ozone_alloc_node(); - - if (!node) - { - RARCH_ERR("ozone node could not be allocated.\n"); - return; - } - - file_list_set_userdata(list, i, node); -} - -static void ozone_list_deep_copy(const file_list_t *src, file_list_t *dst, - size_t first, size_t last) -{ - size_t i, j = 0; - menu_animation_ctx_tag tag = (uintptr_t)dst; - - menu_animation_kill_by_tag(&tag); - - /* use true here because file_list_copy() doesn't free actiondata */ - ozone_free_list_nodes(dst, true); - - file_list_clear(dst); - file_list_reserve(dst, (last + 1) - first); - - for (i = first; i <= last; ++i) - { - struct item_file *d = &dst->list[j]; - struct item_file *s = &src->list[i]; - void *src_udata = s->userdata; - void *src_adata = s->actiondata; - - *d = *s; - d->alt = string_is_empty(d->alt) ? NULL : strdup(d->alt); - d->path = string_is_empty(d->path) ? NULL : strdup(d->path); - d->label = string_is_empty(d->label) ? NULL : strdup(d->label); - - if (src_udata) - file_list_set_userdata(dst, j, (void*)ozone_copy_node((const ozone_node_t*)src_udata)); - - if (src_adata) - { - void *data = malloc(sizeof(menu_file_list_cbs_t)); - memcpy(data, src_adata, sizeof(menu_file_list_cbs_t)); - file_list_set_actiondata(dst, j, data); - } - - ++j; - } - - dst->size = j; -} - -static void ozone_list_cache(void *data, - enum menu_list_type type, unsigned action) -{ - size_t y, entries_end; - unsigned i; - unsigned video_info_height; - float bottom_boundary; - ozone_node_t *first_node; - unsigned first = 0; - unsigned last = 0; - file_list_t *selection_buf = NULL; - ozone_handle_t *ozone = (ozone_handle_t*)data; - - if (!ozone) - return; - - ozone->need_compute = true; - ozone->selection_old_list = ozone->selection; - ozone->scroll_old = ozone->animations.scroll_y; - ozone->is_playlist_old = ozone->is_playlist; - - /* Deep copy visible elements */ - video_driver_get_size(NULL, &video_info_height); - y = ENTRIES_START_Y; - entries_end = menu_entries_get_size(); - selection_buf = menu_entries_get_selection_buf_ptr(0); - bottom_boundary = video_info_height - 87 - 78; - - for (i = 0; i < entries_end; i++) - { - ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); - - if (!node) - continue; - - if (y + ozone->animations.scroll_y + node->height + 20 < ENTRIES_START_Y) - { - first++; - goto text_iterate; - } - else if (y + ozone->animations.scroll_y - node->height - 20 > bottom_boundary) - goto text_iterate; - - last++; -text_iterate: - y += node->height; - } - - last -= 1; - last += first; - - first_node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, first); - ozone->old_list_offset_y = first_node->position_y; - - ozone_list_deep_copy(selection_buf, ozone->selection_buf_old, first, last); -} - -static int ozone_environ_cb(enum menu_environ_cb type, void *data, void *userdata) -{ - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - - if (!ozone) - return -1; - - switch (type) - { - case MENU_ENVIRON_RESET_HORIZONTAL_LIST: - if (!ozone) - return -1; - - ozone_refresh_horizontal_list(ozone); - break; - default: - return -1; - } - - return 0; -} - -static void ozone_messagebox(void *data, const char *message) -{ - ozone_handle_t *ozone = (ozone_handle_t*) data; - - if (!ozone || string_is_empty(message)) - return; - - if (ozone->pending_message) - { - free(ozone->pending_message); - ozone->pending_message = NULL; - } - - ozone->pending_message = strdup(message); - ozone->messagebox_state = true || menu_input_dialog_get_display_kb(); - ozone->should_draw_messagebox = true; -} - -static int ozone_deferred_push_content_actions(menu_displaylist_info_t *info) -{ - if (!menu_displaylist_ctl( - DISPLAYLIST_HORIZONTAL_CONTENT_ACTIONS, info)) - return -1; - menu_displaylist_process(info); - menu_displaylist_info_free(info); - return 0; -} - -static int ozone_list_bind_init_compare_label(menu_file_list_cbs_t *cbs) -{ - if (cbs && cbs->enum_idx != MSG_UNKNOWN) - { - switch (cbs->enum_idx) - { - case MENU_ENUM_LABEL_CONTENT_ACTIONS: - cbs->action_deferred_push = ozone_deferred_push_content_actions; - break; - default: - return -1; - } - } - - return 0; -} - -static int ozone_list_bind_init(menu_file_list_cbs_t *cbs, - const char *path, const char *label, unsigned type, size_t idx) -{ - if (ozone_list_bind_init_compare_label(cbs) == 0) - return 0; - - return -1; -} - -menu_ctx_driver_t menu_ctx_ozone = { - NULL, /* set_texture */ - ozone_messagebox, - ozone_menu_iterate, - ozone_render, - ozone_frame, - ozone_init, - ozone_free, - ozone_context_reset, - ozone_context_destroy, - ozone_populate_entries, - ozone_toggle, - ozone_navigation_clear, - ozone_navigation_pointer_changed, - ozone_navigation_pointer_changed, - ozone_navigation_set, - ozone_navigation_pointer_changed, - ozone_navigation_alphabet, - ozone_navigation_alphabet, - ozone_menu_init_list, - ozone_list_insert, - NULL, /* list_prepend */ - ozone_list_free, - ozone_list_clear, - ozone_list_cache, - ozone_list_push, - ozone_list_get_selection, - ozone_list_get_size, - ozone_list_get_entry, - NULL, /* list_set_selection */ - ozone_list_bind_init, /* bind_init */ - NULL, /* load_image */ - "ozone", - ozone_environ_cb, - NULL, /* pointer_tap */ - NULL, /* update_thumbnail_path */ - NULL, /* update_thumbnail_image */ - NULL, /* set_thumbnail_system */ - NULL, /* set_thumbnail_content */ - menu_display_osk_ptr_at_pos, - NULL, /* update_savestate_thumbnail_path */ - NULL /* update_savestate_thumbnail_image */ -}; diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c new file mode 100644 index 0000000000..556b59fe20 --- /dev/null +++ b/menu/drivers/ozone/ozone.c @@ -0,0 +1,1856 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" +#include "ozone_display.h" +#include "ozone_theme.h" +#include "ozone_texture.h" +#include "ozone_sidebar.h" + +#include +#include +#include +#include +#include +#include + +#include "../menu_generic.h" + +#include "../../menu_driver.h" +#include "../../menu_animation.h" +#include "../../menu_input.h" + +#include "../../widgets/menu_input_dialog.h" +#include "../../widgets/menu_osk.h" + +#include "../../../configuration.h" +#include "../../../content.h" +#include "../../../core_info.h" +#include "../../../core.h" +#include "../../../verbosity.h" +#include "../../../tasks/tasks_internal.h" + +ozone_node_t *ozone_alloc_node() +{ + ozone_node_t *node = (ozone_node_t*)malloc(sizeof(*node)); + + node->height = 0; + node->position_y = 0; + node->console_name = NULL; + node->icon = 0; + node->content_icon = 0; + + return node; +} + +size_t ozone_list_get_size(void *data, enum menu_list_type type) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return 0; + + switch (type) + { + case MENU_LIST_PLAIN: + return menu_entries_get_stack_size(0); + case MENU_LIST_HORIZONTAL: + if (ozone && ozone->horizontal_list) + return file_list_get_size(ozone->horizontal_list); + break; + case MENU_LIST_TABS: + return ozone->system_tab_end; + } + + return 0; +} + +static void ozone_free_node(ozone_node_t *node) +{ + if (!node) + return; + + if (node->console_name) + free(node->console_name); + + free(node); +} + +void ozone_free_list_nodes(file_list_t *list, bool actiondata) +{ + unsigned i, size = (unsigned)file_list_get_size(list); + + for (i = 0; i < size; ++i) + { + ozone_free_node((ozone_node_t*)file_list_get_userdata_at_offset(list, i)); + + /* file_list_set_userdata() doesn't accept NULL */ + list->list[i].userdata = NULL; + + if (actiondata) + file_list_free_actiondata(list, i); + } +} + +static void *ozone_init(void **userdata, bool video_is_threaded) +{ + bool fallback_color_theme = false; + unsigned width, height, color_theme = 0; + ozone_handle_t *ozone = NULL; + settings_t *settings = config_get_ptr(); + menu_handle_t *menu = (menu_handle_t*)calloc(1, sizeof(*menu)); + + if (!menu) + return false; + + if (!menu_display_init_first_driver(video_is_threaded)) + goto error; + + video_driver_get_size(&width, &height); + + ozone = (ozone_handle_t*)calloc(1, sizeof(ozone_handle_t)); + + if (!ozone) + goto error; + + *userdata = ozone; + + ozone->selection_buf_old = (file_list_t*)calloc(1, sizeof(file_list_t)); + + ozone->draw_sidebar = true; + ozone->sidebar_offset = 0; + ozone->pending_message = NULL; + ozone->is_playlist = false; + ozone->categories_selection_ptr = 0; + ozone->pending_message = NULL; + + ozone->system_tab_end = 0; + ozone->tabs[ozone->system_tab_end] = OZONE_SYSTEM_TAB_MAIN; + if (settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_SETTINGS; + if (settings->bools.menu_content_show_favorites) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_FAVORITES; + if (settings->bools.menu_content_show_history) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_HISTORY; +#ifdef HAVE_IMAGEVIEWER + if (settings->bools.menu_content_show_images) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_IMAGES; +#endif + if (settings->bools.menu_content_show_music) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_MUSIC; +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + if (settings->bools.menu_content_show_video) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_VIDEO; +#endif +#ifdef HAVE_NETWORKING + if (settings->bools.menu_content_show_netplay) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_NETPLAY; +#endif +#ifdef HAVE_LIBRETRODB + if (settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_ADD; +#endif + + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + + menu_display_set_width(width); + menu_display_set_height(height); + + menu_display_allocate_white_texture(); + + ozone->horizontal_list = (file_list_t*)calloc(1, sizeof(file_list_t)); + + if (ozone->horizontal_list) + ozone_init_horizontal_list(ozone); + + /* Theme */ + if (settings->bools.menu_use_preferred_system_color_theme) + { +#ifdef HAVE_LIBNX + if (R_SUCCEEDED(setsysInitialize())) + { + ColorSetId theme; + setsysGetColorSetId(&theme); + color_theme = (theme == ColorSetId_Dark) ? 1 : 0; + ozone_set_color_theme(ozone, color_theme); + settings->uints.menu_ozone_color_theme = color_theme; + settings->bools.menu_preferred_system_color_theme_set = true; + setsysExit(); + } + else + fallback_color_theme = true; +#endif + } + else + fallback_color_theme = true; + + if (fallback_color_theme) + { + color_theme = settings->uints.menu_ozone_color_theme; + ozone_set_color_theme(ozone, color_theme); + } + + ozone->need_compute = false; + ozone->animations.scroll_y = 0.0f; + ozone->animations.scroll_y_sidebar = 0.0f; + + /* Assets path */ + fill_pathname_join( + ozone->assets_path, + settings->paths.directory_assets, + "ozone", + sizeof(ozone->assets_path) + ); + + /* PNG path */ + fill_pathname_join( + ozone->png_path, + ozone->assets_path, + "png", + sizeof(ozone->png_path) + ); + + /* Icons path */ + fill_pathname_join( + ozone->icons_path, + ozone->png_path, + "icons", + sizeof(ozone->icons_path) + ); + + /* Sidebar path */ + fill_pathname_join( + ozone->tab_path, + ozone->png_path, + "sidebar", + sizeof(ozone->tab_path) + ); + + last_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme; + + return menu; + +error: + if (ozone->horizontal_list) + { + ozone_free_list_nodes(ozone->horizontal_list, false); + file_list_free(ozone->horizontal_list); + } + ozone->horizontal_list = NULL; + + if (menu) + free(menu); + + return NULL; +} + +static void ozone_free(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (ozone) + { + video_coord_array_free(&ozone->raster_blocks.footer.carr); + video_coord_array_free(&ozone->raster_blocks.title.carr); + video_coord_array_free(&ozone->raster_blocks.time.carr); + video_coord_array_free(&ozone->raster_blocks.entries_label.carr); + video_coord_array_free(&ozone->raster_blocks.entries_sublabel.carr); + video_coord_array_free(&ozone->raster_blocks.sidebar.carr); + + font_driver_bind_block(NULL, NULL); + + if (ozone->selection_buf_old) + { + ozone_free_list_nodes(ozone->selection_buf_old, false); + file_list_free(ozone->selection_buf_old); + } + + if (ozone->horizontal_list) + { + ozone_free_list_nodes(ozone->horizontal_list, false); + file_list_free(ozone->horizontal_list); + } + + if (!string_is_empty(ozone->pending_message)) + free(ozone->pending_message); + } +} + +static void ozone_context_reset(void *data, bool is_threaded) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (ozone) + { + ozone->has_all_assets = true; + + /* Fonts init */ + unsigned i; + unsigned size; + char font_path[PATH_MAX_LENGTH]; + + fill_pathname_join(font_path, ozone->assets_path, "regular.ttf", sizeof(font_path)); + ozone->fonts.footer = menu_display_font_file(font_path, FONT_SIZE_FOOTER, is_threaded); + ozone->fonts.entries_label = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_LABEL, is_threaded); + ozone->fonts.entries_sublabel = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_SUBLABEL, is_threaded); + ozone->fonts.time = menu_display_font_file(font_path, FONT_SIZE_TIME, is_threaded); + ozone->fonts.sidebar = menu_display_font_file(font_path, FONT_SIZE_SIDEBAR, is_threaded); + + fill_pathname_join(font_path, ozone->assets_path, "bold.ttf", sizeof(font_path)); + ozone->fonts.title = menu_display_font_file(font_path, FONT_SIZE_TITLE, is_threaded); + + if ( + !ozone->fonts.footer || + !ozone->fonts.entries_label || + !ozone->fonts.entries_sublabel || + !ozone->fonts.time || + !ozone->fonts.sidebar || + !ozone->fonts.title + ) + { + ozone->has_all_assets = false; + } + + /* Naive font size */ + ozone->title_font_glyph_width = FONT_SIZE_TITLE * 3/4; + ozone->entry_font_glyph_width = FONT_SIZE_ENTRIES_LABEL * 3/4; + ozone->sublabel_font_glyph_width = FONT_SIZE_ENTRIES_SUBLABEL * 3/4; + + /* More realistic font size */ + size = font_driver_get_message_width(ozone->fonts.title, "a", 1, 1); + if (size) + ozone->title_font_glyph_width = size; + size = font_driver_get_message_width(ozone->fonts.entries_label, "a", 1, 1); + if (size) + ozone->entry_font_glyph_width = size; + size = font_driver_get_message_width(ozone->fonts.entries_sublabel, "a", 1, 1); + if (size) + ozone->sublabel_font_glyph_width = size; + + /* Textures init */ + for (i = 0; i < OZONE_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strlcpy(filename, OZONE_TEXTURES_FILES[i], sizeof(filename)); + strlcat(filename, ".png", sizeof(filename)); + + if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + ozone->has_all_assets = false; + } + + /* Sidebar textures */ + for (i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strlcpy(filename, OZONE_TAB_TEXTURES_FILES[i], sizeof(filename)); + strlcat(filename, ".png", sizeof(filename)); + + if (!menu_display_reset_textures_list(filename, ozone->tab_path, &ozone->tab_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + ozone->has_all_assets = false; + } + + /* Theme textures */ + if (!ozone_reset_theme_textures(ozone)) + ozone->has_all_assets = false; + + /* Icons textures init */ + for (i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) + if (!menu_display_reset_textures_list(ozone_entries_icon_texture_path(ozone, i), ozone->icons_path, &ozone->icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + ozone->has_all_assets = false; + + menu_display_allocate_white_texture(); + + /* Horizontal list */ + ozone_context_reset_horizontal_list(ozone); + + /* State reset */ + ozone->frame_count = 0; + ozone->fade_direction = false; + ozone->cursor_in_sidebar = false; + ozone->cursor_in_sidebar_old = false; + ozone->draw_old_list = false; + ozone->messagebox_state = false; + ozone->messagebox_state_old = false; + + /* Animations */ + ozone->animations.cursor_alpha = 1.0f; + ozone->animations.scroll_y = 0.0f; + ozone->animations.list_alpha = 1.0f; + + /* Missing assets message */ + if (!ozone->has_all_assets) + { + RARCH_WARN("[OZONE] Assets missing\n"); + runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false); + } + ozone_restart_cursor_animation(ozone); + } +} + +static void ozone_collapse_end(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone->draw_sidebar = false; +} + +static void ozone_context_destroy(void *data) +{ + unsigned i; + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return; + + /* Theme */ + ozone_unload_theme_textures(ozone); + + /* Icons */ + for (i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) + video_driver_texture_unload(&ozone->icons_textures[i]); + + /* Textures */ + for (i = 0; i < OZONE_TEXTURE_LAST; i++) + video_driver_texture_unload(&ozone->textures[i]); + + /* Icons */ + for (i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) + video_driver_texture_unload(&ozone->tab_textures[i]); + + video_driver_texture_unload(&menu_display_white_texture); + + menu_display_font_free(ozone->fonts.footer); + menu_display_font_free(ozone->fonts.title); + menu_display_font_free(ozone->fonts.time); + menu_display_font_free(ozone->fonts.entries_label); + menu_display_font_free(ozone->fonts.entries_sublabel); + menu_display_font_free(ozone->fonts.sidebar); + + ozone->fonts.footer = NULL; + ozone->fonts.title = NULL; + ozone->fonts.time = NULL; + ozone->fonts.entries_label = NULL; + ozone->fonts.entries_sublabel = NULL; + ozone->fonts.sidebar = NULL; + + menu_animation_ctx_tag tag = (uintptr_t) &ozone_default_theme; + menu_animation_kill_by_tag(&tag); + + /* Horizontal list */ + ozone_context_destroy_horizontal_list(ozone); +} + +static void *ozone_list_get_entry(void *data, + enum menu_list_type type, unsigned i) +{ + size_t list_size = 0; + ozone_handle_t* ozone = (ozone_handle_t*) data; + + switch (type) + { + case MENU_LIST_PLAIN: + { + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + list_size = menu_entries_get_stack_size(0); + if (i < list_size) + return (void*)&menu_stack->list[i]; + } + break; + case MENU_LIST_HORIZONTAL: + if (ozone && ozone->horizontal_list) + list_size = file_list_get_size(ozone->horizontal_list); + if (i < list_size) + return (void*)&ozone->horizontal_list->list[i]; + break; + default: + break; + } + + return NULL; +} + +static int ozone_list_push(void *data, void *userdata, + menu_displaylist_info_t *info, unsigned type) +{ + menu_displaylist_ctx_parse_entry_t entry; + int ret = -1; + unsigned i = 0; + core_info_list_t *list = NULL; + menu_handle_t *menu = (menu_handle_t*)data; + + switch (type) + { + case DISPLAYLIST_LOAD_CONTENT_LIST: + { + settings_t *settings = config_get_ptr(); + + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), + MENU_ENUM_LABEL_FAVORITES, + MENU_SETTING_ACTION, 0, 0); + + core_info_get_list(&list); + if (core_info_list_num_info_files(list)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0); + } + +#ifdef HAVE_LIBRETRODB + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST), + MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST, + MENU_SETTING_ACTION, 0, 0); +#endif + + if (frontend_driver_parse_drive_list(info->list, true) != 0) + menu_entries_append_enum(info->list, "/", + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, + MENU_SETTING_ACTION, 0, 0); + + if (!settings->bools.kiosk_mode_enable) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0); + } + + info->need_push = true; + info->need_refresh = true; + ret = 0; + } + break; + case DISPLAYLIST_MAIN_MENU: + { + settings_t *settings = config_get_ptr(); + rarch_system_info_t *system = runloop_get_system_info(); + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + entry.data = menu; + entry.info = info; + entry.parse_type = PARSE_ACTION; + entry.add_empty_entry = false; + + if (!string_is_empty(system->info.library_name) && + !string_is_equal(system->info.library_name, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE))) + { + entry.enum_idx = MENU_ENUM_LABEL_CONTENT_SETTINGS; + menu_displaylist_setting(&entry); + } + + if (system->load_no_content) + { + entry.enum_idx = MENU_ENUM_LABEL_START_CORE; + menu_displaylist_setting(&entry); + } + +#ifndef HAVE_DYNAMIC + if (frontend_driver_has_fork()) +#endif + { + if (settings->bools.menu_show_load_core) + { + entry.enum_idx = MENU_ENUM_LABEL_CORE_LIST; + menu_displaylist_setting(&entry); + } + } + + if (settings->bools.menu_show_load_content) + { + const struct retro_subsystem_info* subsystem = NULL; + + entry.enum_idx = MENU_ENUM_LABEL_LOAD_CONTENT_LIST; + menu_displaylist_setting(&entry); + + subsystem = system->subsystem.data; + + if (subsystem) + { + for (i = 0; i < (unsigned)system->subsystem.size; i++, subsystem++) + { + char s[PATH_MAX_LENGTH]; + if (content_get_subsystem() == i) + { + if (content_get_subsystem_rom_id() < subsystem->num_roms) + { + snprintf(s, sizeof(s), + "Load %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), + MENU_ENUM_LABEL_SUBSYSTEM_ADD, + MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); + } + else + { + snprintf(s, sizeof(s), + "Start %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_LOAD), + MENU_ENUM_LABEL_SUBSYSTEM_LOAD, + MENU_SETTINGS_SUBSYSTEM_LOAD, 0, 0); + } + } + else + { + snprintf(s, sizeof(s), + "Load %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), + MENU_ENUM_LABEL_SUBSYSTEM_ADD, + MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); + } + } + } + } + + entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; + menu_displaylist_setting(&entry); +#ifdef HAVE_QT + if (settings->bools.desktop_menu_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_SHOW_WIMP; + menu_displaylist_setting(&entry); + } +#endif +#if defined(HAVE_NETWORKING) + if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_ONLINE_UPDATER; + menu_displaylist_setting(&entry); + } +#endif + if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password)) + { + entry.enum_idx = MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS; + menu_displaylist_setting(&entry); + } + + if (settings->bools.kiosk_mode_enable && !string_is_empty(settings->paths.kiosk_mode_password)) + { + entry.enum_idx = MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_information) + { + entry.enum_idx = MENU_ENUM_LABEL_INFORMATION_LIST; + menu_displaylist_setting(&entry); + } + +#ifdef HAVE_LAKKA_SWITCH + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_CPU_PROFILE; + menu_displaylist_setting(&entry); + + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_GPU_PROFILE; + menu_displaylist_setting(&entry); + + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_BACKLIGHT_CONTROL; + menu_displaylist_setting(&entry); +#endif + +#ifndef HAVE_DYNAMIC + entry.enum_idx = MENU_ENUM_LABEL_RESTART_RETROARCH; + menu_displaylist_setting(&entry); +#endif + + if (settings->bools.menu_show_configurations && !settings->bools.kiosk_mode_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_CONFIGURATIONS_LIST; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_help) + { + entry.enum_idx = MENU_ENUM_LABEL_HELP_LIST; + menu_displaylist_setting(&entry); + } + +#if !defined(IOS) + if (settings->bools.menu_show_quit_retroarch) + { + entry.enum_idx = MENU_ENUM_LABEL_QUIT_RETROARCH; + menu_displaylist_setting(&entry); + } +#endif + + if (settings->bools.menu_show_reboot) + { + entry.enum_idx = MENU_ENUM_LABEL_REBOOT; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_shutdown) + { + entry.enum_idx = MENU_ENUM_LABEL_SHUTDOWN; + menu_displaylist_setting(&entry); + } + + info->need_push = true; + ret = 0; + } + break; + } + return ret; +} + +static size_t ozone_list_get_selection(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + + if (!ozone) + return 0; + + return ozone->categories_selection_ptr; +} + +static void ozone_list_clear(file_list_t *list) +{ + menu_animation_ctx_tag tag = (uintptr_t)list; + menu_animation_kill_by_tag(&tag); + + ozone_free_list_nodes(list, false); +} + +static void ozone_list_free(file_list_t *list, size_t a, size_t b) +{ + ozone_list_clear(list); +} + +/* Compute new scroll position + * If the center of the currently selected entry is not in the middle + * And if we can scroll so that it's in the middle + * Then scroll + */ +static void ozone_update_scroll(ozone_handle_t *ozone, bool allow_animation, ozone_node_t *node) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_animation_ctx_tag tag = (uintptr_t) selection_buf; + menu_animation_ctx_entry_t entry; + float new_scroll = 0, entries_middle; + float bottom_boundary, current_selection_middle_onscreen; + unsigned video_info_height; + + video_driver_get_size(NULL, &video_info_height); + + current_selection_middle_onscreen = ENTRIES_START_Y + ozone->animations.scroll_y + node->position_y + node->height / 2; + bottom_boundary = video_info_height - 87 - 78; + entries_middle = video_info_height/2; + + if (current_selection_middle_onscreen != entries_middle) + new_scroll = ozone->animations.scroll_y - (current_selection_middle_onscreen - entries_middle); + + if (new_scroll + ozone->entries_height < bottom_boundary) + new_scroll = -(78 + ozone->entries_height - bottom_boundary); + + if (new_scroll > 0) + new_scroll = 0; + + if (allow_animation) + { + /* Cursor animation */ + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + /* Scroll animation */ + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.scroll_y; + entry.tag = tag; + entry.target_value = new_scroll; + entry.userdata = NULL; + + menu_animation_push(&entry); + } + else + { + ozone->selection_old = ozone->selection; + ozone->animations.cursor_alpha = 1.0f; + ozone->animations.scroll_y = new_scroll; + } +} + +static unsigned ozone_count_lines(const char *str) +{ + unsigned c = 0; + unsigned lines = 1; + + for (c = 0; str[c]; c++) + lines += (str[c] == '\n'); + return lines; +} + +static void ozone_compute_entries_position(ozone_handle_t *ozone) +{ + /* Compute entries height and adjust scrolling if needed */ + unsigned video_info_height; + unsigned video_info_width; + size_t i, entries_end; + file_list_t *selection_buf = NULL; + + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + entries_end = menu_entries_get_size(); + selection_buf = menu_entries_get_selection_buf_ptr(0); + + video_driver_get_size(&video_info_width, &video_info_height); + + ozone->entries_height = 0; + + for (i = 0; i < entries_end; i++) + { + /* Entry */ + menu_entry_t entry; + ozone_node_t *node = NULL; + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, (unsigned)i, NULL, true); + + /* Empty playlist detection: + only one item which icon is + OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO */ + if (ozone->is_playlist && entries_end == 1) + { + menu_texture_item tex = ozone_entries_icon_get_texture(ozone, entry.enum_idx, entry.type, false); + ozone->empty_playlist = tex == ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO]; + } + else + { + ozone->empty_playlist = false; + } + + /* Cache node */ + node = (ozone_node_t*)file_list_get_userdata_at_offset(selection_buf, i); + + if (!node) + continue; + + node->height = (entry.sublabel ? 100 : 60-8); + node->wrap = false; + + if (entry.sublabel) + { + char *sublabel_str = menu_entry_get_sublabel(&entry); + + word_wrap(sublabel_str, sublabel_str, (video_info_width - 548) / ozone->sublabel_font_glyph_width, false); + + unsigned lines = ozone_count_lines(sublabel_str); + + if (lines > 1) + { + node->height += lines * 15; + node->wrap = true; + } + + free(sublabel_str); + } + + node->position_y = ozone->entries_height; + + ozone->entries_height += node->height; + + menu_entry_free(&entry); + } + + /* Update scrolling */ + ozone->selection = menu_navigation_get_selection(); + ozone_update_scroll(ozone, false, (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, ozone->selection)); +} + +static void ozone_render(void *data, bool is_idle) +{ + size_t i; + menu_animation_ctx_delta_t delta; + unsigned end = (unsigned)menu_entries_get_size(); + ozone_handle_t *ozone = (ozone_handle_t*)data; + if (!data) + return; + + if (ozone->need_compute) + { + ozone_compute_entries_position(ozone); + ozone->need_compute = false; + } + + ozone->selection = menu_navigation_get_selection(); + + delta.current = menu_animation_get_delta_time(); + + if (menu_animation_get_ideal_delta_time(&delta)) + menu_animation_update(delta.ideal); + + /* TODO Handle pointer & mouse */ + + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + if (i >= end) + { + i = 0; + menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &i); + } + + menu_animation_ctl(MENU_ANIMATION_CTL_CLEAR_ACTIVE, NULL); +} + +static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_info) +{ + char title[255]; + menu_animation_ctx_ticker_t ticker; + settings_t *settings = config_get_ptr(); + unsigned timedate_offset = 0; + + /* Separator */ + menu_display_draw_quad(video_info, 30, 87, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); + + /* Title */ + ticker.s = title; + ticker.len = (video_info->width - 128 - 47 - 130) / ozone->title_font_glyph_width; + ticker.idx = ozone->frame_count / 20; + ticker.str = ozone->title; + ticker.selected = true; + + menu_animation_ticker(&ticker); + + ozone_draw_text(video_info, ozone, title, 128, 20 + FONT_SIZE_TITLE, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.title, ozone->theme->text_rgba, false); + + /* Icon */ + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_RETROARCH], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + menu_display_blend_end(video_info); + + /* Battery */ + if (video_info->battery_level_enable) + { + char msg[12]; + static retro_time_t last_time = 0; + bool charging = false; + retro_time_t current_time = cpu_features_get_time_usec(); + int percent = 0; + enum frontend_powerstate state = get_last_powerstate(&percent); + + if (state == FRONTEND_POWERSTATE_CHARGING) + charging = true; + + if (current_time - last_time >= INTERVAL_BATTERY_LEVEL_CHECK) + { + last_time = current_time; + task_push_get_powerstate(); + } + + *msg = '\0'; + + if (percent > 0) + { + timedate_offset = 95; + + snprintf(msg, sizeof(msg), "%d%%", percent); + + ozone_draw_text(video_info, ozone, msg, video_info->width - 85, 30 + FONT_SIZE_TIME, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba, false); + + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[charging ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL], video_info->width - 60 - 56, 30 - 28, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + menu_display_blend_end(video_info); + } + } + + /* Timedate */ + if (video_info->timedate_enable) + { + menu_display_ctx_datetime_t datetime; + char timedate[255]; + + timedate[0] = '\0'; + + datetime.s = timedate; + datetime.time_mode = settings->uints.menu_timedate_style; + datetime.len = sizeof(timedate); + + menu_display_timedate(&datetime); + + ozone_draw_text(video_info, ozone, timedate, video_info->width - 87 - timedate_offset, 30 + FONT_SIZE_TIME, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba, false); + + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOCK], video_info->width - 60 - 56 - timedate_offset, 30 - 28, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + menu_display_blend_end(video_info); + } +} + +static void ozone_draw_footer(ozone_handle_t *ozone, video_frame_info_t *video_info, settings_t *settings) +{ + char core_title[255]; + /* Separator */ + menu_display_draw_quad(video_info, 23, video_info->height - 78, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); + + /* Core title or Switch icon */ + if (settings->bools.menu_core_enable && menu_entries_get_core_title(core_title, sizeof(core_title)) == 0) + ozone_draw_text(video_info, ozone, core_title, 59, video_info->height - 49 + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); + else + ozone_draw_icon(video_info, 69, 30, ozone->theme->textures[OZONE_THEME_TEXTURE_SWITCH], 59, video_info->height - 52, video_info->width,video_info->height, 0, 1, NULL); + + /* Buttons */ + + { + unsigned back_width = 215; + unsigned back_height = 49; + unsigned ok_width = 96; + unsigned ok_height = 49; + bool do_swap = video_info->input_menu_swap_ok_cancel_buttons; + + if (do_swap) + { + back_width = 96; + back_height = 49; + ok_width = 215; + ok_height = 49; + } + + menu_display_blend_begin(video_info); + + if (do_swap) + { + ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_B], video_info->width - 133, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_A], video_info->width - 251, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + } + else + { + ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_B], video_info->width - 251, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + ozone_draw_icon(video_info, 25, 25, ozone->theme->textures[OZONE_THEME_TEXTURE_BUTTON_A], video_info->width - 133, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + } + + menu_display_blend_end(video_info); + + ozone_draw_text(video_info, ozone, + do_swap ? + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_OK) : + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK), + video_info->width - back_width, video_info->height - back_height + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); + ozone_draw_text(video_info, ozone, + do_swap ? + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK) : + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_OK), + video_info->width - ok_width, video_info->height - ok_height + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba, false); + } + + menu_display_blend_end(video_info); +} + +static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_animation_ctx_tag tag = (uintptr_t) selection_buf; + + size_t new_selection = menu_navigation_get_selection(); + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, new_selection); + + if (!node) + return; + + if (ozone->selection != new_selection) + { + ozone->selection_old = ozone->selection; + ozone->selection = new_selection; + + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + + menu_animation_kill_by_tag(&tag); + + ozone_update_scroll(ozone, allow_animation, node); + } +} + +static void ozone_navigation_clear(void *data, bool pending_push) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + if (!pending_push) + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_pointer_changed(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_set(void *data, bool scroll) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_alphabet(void *data, size_t *unused) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_messagebox_fadeout_cb(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + free(ozone->pending_message); + ozone->pending_message = NULL; + + ozone->should_draw_messagebox = false; +} + +static void ozone_frame(void *data, video_frame_info_t *video_info) +{ + ozone_handle_t* ozone = (ozone_handle_t*) data; + settings_t *settings = config_get_ptr(); + unsigned color_theme = video_info->ozone_color_theme; + menu_animation_ctx_tag messagebox_tag = (uintptr_t)ozone->pending_message; + bool draw_osk = menu_input_dialog_get_display_kb(); + static bool draw_osk_old = false; + + menu_animation_ctx_entry_t entry; + + if (!ozone) + return; + + /* OSK Fade detection */ + if (draw_osk != draw_osk_old) + { + draw_osk_old = draw_osk; + if (!draw_osk) + { + ozone->should_draw_messagebox = false; + ozone->messagebox_state = false; + ozone->messagebox_state_old = false; + ozone->animations.messagebox_alpha = 0.0f; + } + } + + /* Change theme on the fly */ + if (color_theme != last_color_theme || last_use_preferred_system_color_theme != settings->bools.menu_use_preferred_system_color_theme) + { + if (!settings->bools.menu_use_preferred_system_color_theme) + ozone_set_color_theme(ozone, color_theme); + else + { + video_info->ozone_color_theme = ozone_get_system_theme(); + ozone_set_color_theme(ozone, video_info->ozone_color_theme); + } + + last_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme; + } + + ozone->frame_count++; + + menu_display_set_viewport(video_info->width, video_info->height); + + /* Clear text */ + font_driver_bind_block(ozone->fonts.footer, &ozone->raster_blocks.footer); + font_driver_bind_block(ozone->fonts.title, &ozone->raster_blocks.title); + font_driver_bind_block(ozone->fonts.time, &ozone->raster_blocks.time); + font_driver_bind_block(ozone->fonts.entries_label, &ozone->raster_blocks.entries_label); + font_driver_bind_block(ozone->fonts.entries_sublabel, &ozone->raster_blocks.entries_sublabel); + font_driver_bind_block(ozone->fonts.sidebar, &ozone->raster_blocks.sidebar); + + ozone->raster_blocks.footer.carr.coords.vertices = 0; + ozone->raster_blocks.title.carr.coords.vertices = 0; + ozone->raster_blocks.time.carr.coords.vertices = 0; + ozone->raster_blocks.entries_label.carr.coords.vertices = 0; + ozone->raster_blocks.entries_sublabel.carr.coords.vertices = 0; + ozone->raster_blocks.sidebar.carr.coords.vertices = 0; + + /* Background */ + menu_display_draw_quad(video_info, + 0, 0, video_info->width, video_info->height, + video_info->width, video_info->height, + !video_info->libretro_running ? ozone->theme->background : ozone->theme->background_libretro_running + ); + + /* Header, footer */ + ozone_draw_header(ozone, video_info); + ozone_draw_footer(ozone, video_info, settings); + + /* Sidebar */ + ozone_draw_sidebar(ozone, video_info); + + /* Menu entries */ + menu_display_scissor_begin(video_info, ozone->sidebar_offset + 408, 87, video_info->width - 408 + (-ozone->sidebar_offset), video_info->height - 87 - 78); + + /* Current list */ + ozone_draw_entries(ozone, + video_info, + ozone->selection, + ozone->selection_old, + menu_entries_get_selection_buf_ptr(0), + ozone->animations.list_alpha, + ozone->animations.scroll_y, + ozone->is_playlist + ); + + /* Old list */ + if (ozone->draw_old_list) + ozone_draw_entries(ozone, + video_info, + ozone->selection_old_list, + ozone->selection_old_list, + ozone->selection_buf_old, + ozone->animations.list_alpha, + ozone->scroll_old, + ozone->is_playlist_old + ); + + menu_display_scissor_end(video_info); + + /* Flush first layer of text */ + font_driver_flush(video_info->width, video_info->height, ozone->fonts.footer, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.title, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.time, video_info); + + font_driver_bind_block(ozone->fonts.footer, NULL); + font_driver_bind_block(ozone->fonts.title, NULL); + font_driver_bind_block(ozone->fonts.time, NULL); + font_driver_bind_block(ozone->fonts.entries_label, NULL); + + /* Message box & OSK - second layer of text */ + ozone->raster_blocks.footer.carr.coords.vertices = 0; + ozone->raster_blocks.entries_label.carr.coords.vertices = 0; + + if (ozone->should_draw_messagebox || draw_osk) + { + /* Fade in animation */ + if (ozone->messagebox_state_old != ozone->messagebox_state && ozone->messagebox_state) + { + ozone->messagebox_state_old = ozone->messagebox_state; + + menu_animation_kill_by_tag(&messagebox_tag); + ozone->animations.messagebox_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.messagebox_alpha; + entry.tag = messagebox_tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + } + /* Fade out animation */ + else if (ozone->messagebox_state_old != ozone->messagebox_state && !ozone->messagebox_state) + { + ozone->messagebox_state_old = ozone->messagebox_state; + ozone->messagebox_state = false; + + menu_animation_kill_by_tag(&messagebox_tag); + ozone->animations.messagebox_alpha = 1.0f; + + entry.cb = ozone_messagebox_fadeout_cb; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.messagebox_alpha; + entry.tag = messagebox_tag; + entry.target_value = 0.0f; + entry.userdata = ozone; + + menu_animation_push(&entry); + } + + ozone_draw_backdrop(video_info, fmin(ozone->animations.messagebox_alpha, 0.75f)); + + if (draw_osk) + { + const char *label = menu_input_dialog_get_label_buffer(); + const char *str = menu_input_dialog_get_buffer(); + + ozone_draw_osk(ozone, video_info, label, str); + } + else + { + ozone_draw_messagebox(ozone, video_info, ozone->pending_message); + } + } + + font_driver_flush(video_info->width, video_info->height, ozone->fonts.footer, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_label, video_info); + + menu_display_unset_viewport(video_info->width, video_info->height); +} + +static void ozone_set_header(ozone_handle_t *ozone) +{ + if (ozone->categories_selection_ptr <= ozone->system_tab_end) + { + menu_entries_get_title(ozone->title, sizeof(ozone->title)); + } + else if (ozone->horizontal_list) + { + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, ozone->categories_selection_ptr - ozone->system_tab_end-1); + + if (node && node->console_name) + strlcpy(ozone->title, node->console_name, sizeof(ozone->title)); + } +} + +static void ozone_animation_end(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone->draw_old_list = false; +} + +static void ozone_list_open(ozone_handle_t *ozone) +{ + struct menu_animation_ctx_entry entry; + + ozone->draw_old_list = true; + + /* Left/right animation */ + ozone->animations.list_alpha = 0.0f; + + entry.cb = ozone_animation_end; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.list_alpha; + entry.tag = (uintptr_t) NULL; + entry.target_value = 1.0f; + entry.userdata = ozone; + + menu_animation_push(&entry); + + /* Sidebar animation */ + if (ozone->depth == 1) + { + ozone->draw_sidebar = true; + + entry.cb = NULL; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->sidebar_offset; + entry.tag = (uintptr_t) NULL; + entry.target_value = 0.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + } + else if (ozone->depth > 1) + { + struct menu_animation_ctx_entry entry; + + entry.cb = ozone_collapse_end; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->sidebar_offset; + entry.tag = (uintptr_t) NULL; + entry.target_value = -408.0f; + entry.userdata = (void*) ozone; + + menu_animation_push(&entry); + } +} + +static void ozone_populate_entries(void *data, const char *path, const char *label, unsigned k) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return; + + ozone_set_header(ozone); + + if (menu_driver_ctl(RARCH_MENU_CTL_IS_PREVENT_POPULATE, NULL)) + { + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + + /* TODO Update thumbnails */ + ozone_selection_changed(ozone, false); + return; + } + + ozone->need_compute = true; + + int new_depth = (int)ozone_list_get_size(ozone, MENU_LIST_PLAIN); + + ozone->fade_direction = new_depth <= ozone->depth; + ozone->depth = new_depth; + ozone->is_playlist = ozone_is_playlist(ozone); + + if (ozone->categories_selection_ptr == ozone->categories_active_idx_old) + { + ozone_list_open(ozone); + } +} + +static int ozone_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_action action) +{ + int new_selection; + enum menu_action new_action; + menu_animation_ctx_tag tag; + + file_list_t *selection_buf = NULL; + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + unsigned horizontal_list_size = 0; + + if (ozone->horizontal_list) + horizontal_list_size = ozone->horizontal_list->size; + + ozone->messagebox_state = false || menu_input_dialog_get_display_kb(); + + if (!ozone) + return generic_menu_iterate(menu, userdata, action); + + selection_buf = menu_entries_get_selection_buf_ptr(0); + tag = (uintptr_t)selection_buf; + new_action = action; + + /* Inputs override */ + switch (action) + { + case MENU_ACTION_DOWN: + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + + new_selection = (ozone->categories_selection_ptr + 1); + + if (new_selection >= ozone->system_tab_end + horizontal_list_size + 1) + new_selection = 0; + + ozone_sidebar_goto(ozone, new_selection); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_UP: + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + + new_selection = ozone->categories_selection_ptr - 1; + + if (new_selection < 0) + new_selection = horizontal_list_size + ozone->system_tab_end; + + ozone_sidebar_goto(ozone, new_selection); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_LEFT: + if (ozone->cursor_in_sidebar) + { + new_action = MENU_ACTION_NOOP; + break; + } + else if (ozone->depth > 1) + break; + + ozone_go_to_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_RIGHT: + if (!ozone->cursor_in_sidebar) + { + if (ozone->depth == 1) + new_action = MENU_ACTION_NOOP; + break; + } + + ozone_leave_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_OK: + if (ozone->cursor_in_sidebar) + { + ozone_leave_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + break; + } + + break; + case MENU_ACTION_CANCEL: + if (ozone->cursor_in_sidebar) + { + /* Go back to main menu tab */ + if (ozone->categories_selection_ptr != 0) + ozone_sidebar_goto(ozone, 0); + + new_action = MENU_ACTION_NOOP; + break; + } + + if (menu_entries_get_stack_size(0) == 1) + { + ozone_go_to_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + } + break; + default: + break; + } + + return generic_menu_iterate(menu, userdata, new_action); +} + +/* TODO Fancy toggle animation */ + +static void ozone_toggle(void *userdata, bool menu_on) +{ + bool tmp = false; + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + if (!ozone) + return; + + tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL); + + if (tmp) + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + else + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + + if (ozone->depth == 1) + { + ozone->draw_sidebar = true; + ozone->sidebar_offset = 0.0f; + } +} + +static bool ozone_menu_init_list(void *data) +{ + menu_displaylist_info_t info; + + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + + menu_displaylist_info_init(&info); + + info.label = strdup( + msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)); + info.exts = + strdup(file_path_str(FILE_PATH_LPL_EXTENSION_NO_DOT)); + info.type_default = FILE_TYPE_PLAIN; + info.enum_idx = MENU_ENUM_LABEL_MAIN_MENU; + + menu_entries_append_enum(menu_stack, info.path, + info.label, + MENU_ENUM_LABEL_MAIN_MENU, + info.type, info.flags, 0); + + info.list = selection_buf; + + if (!menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info)) + goto error; + + info.need_push = true; + + if (!menu_displaylist_process(&info)) + goto error; + + menu_displaylist_info_free(&info); + return true; + +error: + menu_displaylist_info_free(&info); + return false; +} + +static ozone_node_t *ozone_copy_node(const ozone_node_t *old_node) +{ + ozone_node_t *new_node = (ozone_node_t*)malloc(sizeof(*new_node)); + + *new_node = *old_node; + + return new_node; +} + +static void ozone_list_insert(void *userdata, + file_list_t *list, + const char *path, + const char *fullpath, + const char *label, + size_t list_size, + unsigned type) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone_node_t *node = NULL; + int i = (int)list_size; + + if (!ozone || !list) + return; + + ozone->need_compute = true; + + node = (ozone_node_t*)file_list_get_userdata_at_offset(list, i); + + if (!node) + node = ozone_alloc_node(); + + if (!node) + { + RARCH_ERR("ozone node could not be allocated.\n"); + return; + } + + file_list_set_userdata(list, i, node); +} + +static void ozone_list_deep_copy(const file_list_t *src, file_list_t *dst, + size_t first, size_t last) +{ + size_t i, j = 0; + menu_animation_ctx_tag tag = (uintptr_t)dst; + + menu_animation_kill_by_tag(&tag); + + /* use true here because file_list_copy() doesn't free actiondata */ + ozone_free_list_nodes(dst, true); + + file_list_clear(dst); + file_list_reserve(dst, (last + 1) - first); + + for (i = first; i <= last; ++i) + { + struct item_file *d = &dst->list[j]; + struct item_file *s = &src->list[i]; + void *src_udata = s->userdata; + void *src_adata = s->actiondata; + + *d = *s; + d->alt = string_is_empty(d->alt) ? NULL : strdup(d->alt); + d->path = string_is_empty(d->path) ? NULL : strdup(d->path); + d->label = string_is_empty(d->label) ? NULL : strdup(d->label); + + if (src_udata) + file_list_set_userdata(dst, j, (void*)ozone_copy_node((const ozone_node_t*)src_udata)); + + if (src_adata) + { + void *data = malloc(sizeof(menu_file_list_cbs_t)); + memcpy(data, src_adata, sizeof(menu_file_list_cbs_t)); + file_list_set_actiondata(dst, j, data); + } + + ++j; + } + + dst->size = j; +} + +static void ozone_list_cache(void *data, + enum menu_list_type type, unsigned action) +{ + size_t y, entries_end; + unsigned i; + unsigned video_info_height; + float bottom_boundary; + ozone_node_t *first_node; + unsigned first = 0; + unsigned last = 0; + file_list_t *selection_buf = NULL; + ozone_handle_t *ozone = (ozone_handle_t*)data; + + if (!ozone) + return; + + ozone->need_compute = true; + ozone->selection_old_list = ozone->selection; + ozone->scroll_old = ozone->animations.scroll_y; + ozone->is_playlist_old = ozone->is_playlist; + + /* Deep copy visible elements */ + video_driver_get_size(NULL, &video_info_height); + y = ENTRIES_START_Y; + entries_end = menu_entries_get_size(); + selection_buf = menu_entries_get_selection_buf_ptr(0); + bottom_boundary = video_info_height - 87 - 78; + + for (i = 0; i < entries_end; i++) + { + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + if (!node) + continue; + + if (y + ozone->animations.scroll_y + node->height + 20 < ENTRIES_START_Y) + { + first++; + goto text_iterate; + } + else if (y + ozone->animations.scroll_y - node->height - 20 > bottom_boundary) + goto text_iterate; + + last++; +text_iterate: + y += node->height; + } + + last -= 1; + last += first; + + first_node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, first); + ozone->old_list_offset_y = first_node->position_y; + + ozone_list_deep_copy(selection_buf, ozone->selection_buf_old, first, last); +} + +static int ozone_environ_cb(enum menu_environ_cb type, void *data, void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + if (!ozone) + return -1; + + switch (type) + { + case MENU_ENVIRON_RESET_HORIZONTAL_LIST: + if (!ozone) + return -1; + + ozone_refresh_horizontal_list(ozone); + break; + default: + return -1; + } + + return 0; +} + +static void ozone_messagebox(void *data, const char *message) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone || string_is_empty(message)) + return; + + if (ozone->pending_message) + { + free(ozone->pending_message); + ozone->pending_message = NULL; + } + + ozone->pending_message = strdup(message); + ozone->messagebox_state = true || menu_input_dialog_get_display_kb(); + ozone->should_draw_messagebox = true; +} + +static int ozone_deferred_push_content_actions(menu_displaylist_info_t *info) +{ + if (!menu_displaylist_ctl( + DISPLAYLIST_HORIZONTAL_CONTENT_ACTIONS, info)) + return -1; + menu_displaylist_process(info); + menu_displaylist_info_free(info); + return 0; +} + +static int ozone_list_bind_init_compare_label(menu_file_list_cbs_t *cbs) +{ + if (cbs && cbs->enum_idx != MSG_UNKNOWN) + { + switch (cbs->enum_idx) + { + case MENU_ENUM_LABEL_CONTENT_ACTIONS: + cbs->action_deferred_push = ozone_deferred_push_content_actions; + break; + default: + return -1; + } + } + + return 0; +} + +static int ozone_list_bind_init(menu_file_list_cbs_t *cbs, + const char *path, const char *label, unsigned type, size_t idx) +{ + if (ozone_list_bind_init_compare_label(cbs) == 0) + return 0; + + return -1; +} + +menu_ctx_driver_t menu_ctx_ozone = { + NULL, /* set_texture */ + ozone_messagebox, + ozone_menu_iterate, + ozone_render, + ozone_frame, + ozone_init, + ozone_free, + ozone_context_reset, + ozone_context_destroy, + ozone_populate_entries, + ozone_toggle, + ozone_navigation_clear, + ozone_navigation_pointer_changed, + ozone_navigation_pointer_changed, + ozone_navigation_set, + ozone_navigation_pointer_changed, + ozone_navigation_alphabet, + ozone_navigation_alphabet, + ozone_menu_init_list, + ozone_list_insert, + NULL, /* list_prepend */ + ozone_list_free, + ozone_list_clear, + ozone_list_cache, + ozone_list_push, + ozone_list_get_selection, + ozone_list_get_size, + ozone_list_get_entry, + NULL, /* list_set_selection */ + ozone_list_bind_init, /* bind_init */ + NULL, /* load_image */ + "ozone", + ozone_environ_cb, + NULL, /* pointer_tap */ + NULL, /* update_thumbnail_path */ + NULL, /* update_thumbnail_image */ + NULL, /* set_thumbnail_system */ + NULL, /* set_thumbnail_content */ + menu_display_osk_ptr_at_pos, + NULL, /* update_savestate_thumbnail_path */ + NULL /* update_savestate_thumbnail_image */ +}; diff --git a/menu/drivers/ozone/ozone.h b/menu/drivers/ozone/ozone.h new file mode 100644 index 0000000000..5438714485 --- /dev/null +++ b/menu/drivers/ozone/ozone.h @@ -0,0 +1,210 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef _OZONE_H +#define _OZONE_H + +typedef struct ozone_handle ozone_handle_t; + +#include "ozone_theme.h" +#include "ozone_sidebar.h" + +#include + +#include "../../menu_driver.h" +#include "../../../retroarch.h" + +#define FONT_SIZE_FOOTER 18 +#define FONT_SIZE_TITLE 36 +#define FONT_SIZE_TIME 22 +#define FONT_SIZE_ENTRIES_LABEL 24 +#define FONT_SIZE_ENTRIES_SUBLABEL 18 +#define FONT_SIZE_SIDEBAR 24 + +#define ANIMATION_PUSH_ENTRY_DURATION 10 +#define ANIMATION_CURSOR_DURATION 8 +#define ANIMATION_CURSOR_PULSE 30 + +#define ENTRIES_START_Y 127 + +#define INTERVAL_BATTERY_LEVEL_CHECK (30 * 1000000) +#define INTERVAL_OSK_CURSOR (0.5f * 1000000) + +typedef struct ozone_handle +{ + uint64_t frame_count; + + struct + { + font_data_t *footer; + font_data_t *title; + font_data_t *time; + font_data_t *entries_label; + font_data_t *entries_sublabel; + font_data_t *sidebar; + } fonts; + + struct + { + video_font_raster_block_t footer; + video_font_raster_block_t title; + video_font_raster_block_t time; + video_font_raster_block_t entries_label; + video_font_raster_block_t entries_sublabel; + video_font_raster_block_t sidebar; + } raster_blocks; + + menu_texture_item textures[OZONE_THEME_TEXTURE_LAST]; + menu_texture_item icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LAST]; + menu_texture_item tab_textures[OZONE_TAB_TEXTURE_LAST]; + + char title[PATH_MAX_LENGTH]; + + char assets_path[PATH_MAX_LENGTH]; + char png_path[PATH_MAX_LENGTH]; + char icons_path[PATH_MAX_LENGTH]; + char tab_path[PATH_MAX_LENGTH]; + + uint8_t system_tab_end; + uint8_t tabs[OZONE_SYSTEM_TAB_LAST]; + + size_t categories_selection_ptr; /* active tab id */ + size_t categories_active_idx_old; + + bool cursor_in_sidebar; + bool cursor_in_sidebar_old; + + struct + { + float cursor_alpha; + float scroll_y; + float scroll_y_sidebar; + + float list_alpha; + + float messagebox_alpha; + } animations; + + bool fade_direction; /* false = left to right, true = right to left */ + + size_t selection; /* currently selected entry */ + size_t selection_old; /* previously selected entry (for fancy animation) */ + size_t selection_old_list; + + unsigned entries_height; + + int depth; + + bool draw_sidebar; + float sidebar_offset; + + unsigned title_font_glyph_width; + unsigned entry_font_glyph_width; + unsigned sublabel_font_glyph_width; + + ozone_theme_t *theme; + + struct { + float selection_border[16]; + float selection[16]; + float entries_border[16]; + float entries_icon[16]; + float entries_checkmark[16]; + float cursor_alpha[16]; + + unsigned cursor_state; /* 0 -> 1 -> 0 -> 1 [...] */ + float cursor_border[16]; + float message_background[16]; + } theme_dynamic; + + bool need_compute; + + file_list_t *selection_buf_old; + + bool draw_old_list; + float scroll_old; + + char *pending_message; + bool has_all_assets; + + bool is_playlist; + bool is_playlist_old; + + bool empty_playlist; + + bool osk_cursor; /* true = display it, false = don't */ + bool messagebox_state; + bool messagebox_state_old; + bool should_draw_messagebox; + + unsigned old_list_offset_y; + + file_list_t *horizontal_list; /* console tabs */ +} ozone_handle_t; + +/* If you change this struct, also + change ozone_alloc_node and + ozone_copy_node */ +typedef struct ozone_node +{ + /* Entries */ + unsigned height; + unsigned position_y; + bool wrap; + + /* Console tabs */ + char *console_name; + uintptr_t icon; + uintptr_t content_icon; +} ozone_node_t; + +void ozone_draw_entries(ozone_handle_t *ozone, video_frame_info_t *video_info, + unsigned selection, unsigned selection_old, + file_list_t *selection_buf, float alpha, float scroll_y, + bool is_playlist); + +void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info); + +void ozone_change_tab(ozone_handle_t *ozone, + enum msg_hash_enums tab, + enum menu_settings_type type); + +void ozone_sidebar_goto(ozone_handle_t *ozone, unsigned new_selection); + +unsigned ozone_get_sidebar_height(ozone_handle_t *ozone); + +unsigned ozone_get_selected_sidebar_y_position(ozone_handle_t *ozone); + +void ozone_leave_sidebar(ozone_handle_t *ozone, uintptr_t tag); + +void ozone_go_to_sidebar(ozone_handle_t *ozone, uintptr_t tag); + +void ozone_refresh_horizontal_list(ozone_handle_t *ozone); + +void ozone_init_horizontal_list(ozone_handle_t *ozone); + +void ozone_context_destroy_horizontal_list(ozone_handle_t *ozone); + +void ozone_context_reset_horizontal_list(ozone_handle_t *ozone); + +ozone_node_t *ozone_alloc_node(); + +size_t ozone_list_get_size(void *data, enum menu_list_type type); + +void ozone_free_list_nodes(file_list_t *list, bool actiondata); + +bool ozone_is_playlist(ozone_handle_t *ozone); + +#endif \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_display.c b/menu/drivers/ozone/ozone_display.c new file mode 100644 index 0000000000..a435af7d14 --- /dev/null +++ b/menu/drivers/ozone/ozone_display.c @@ -0,0 +1,430 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" +#include "ozone_display.h" +#include "ozone_theme.h" + +#include +#include +#include +#include +#include + +#include "../../menu_input.h" +#include "../../menu_animation.h" + +#include "../../widgets/menu_input_dialog.h" +#include "../../widgets/menu_osk.h" + +static void ozone_cursor_animation_cb(void *userdata); + +static void ozone_animate_cursor(ozone_handle_t *ozone, float *dst, float *target) +{ + menu_animation_ctx_entry_t entry; + int i; + + entry.easing_enum = EASING_OUT_QUAD; + entry.tag = (uintptr_t) &ozone_default_theme; + entry.duration = ANIMATION_CURSOR_PULSE; + entry.userdata = ozone; + + for (i = 0; i < 16; i++) + { + if (i == 3 || i == 7 || i == 11 || i == 15) + continue; + + if (i == 14) + entry.cb = ozone_cursor_animation_cb; + else + entry.cb = NULL; + + entry.subject = &dst[i]; + entry.target_value = target[i]; + + menu_animation_push(&entry); + } +} + +static void ozone_cursor_animation_cb(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + float *target = NULL; + + switch (ozone->theme_dynamic.cursor_state) + { + case 0: + target = ozone->theme->cursor_border_1; + break; + case 1: + target = ozone->theme->cursor_border_0; + break; + } + + ozone->theme_dynamic.cursor_state = (ozone->theme_dynamic.cursor_state + 1) % 2; + + ozone_animate_cursor(ozone, ozone->theme_dynamic.cursor_border, target); +} + +void ozone_restart_cursor_animation(ozone_handle_t *ozone) +{ + menu_animation_ctx_tag tag = (uintptr_t) &ozone_default_theme; + + if (!ozone->has_all_assets) + return; + + ozone->theme_dynamic.cursor_state = 1; + memcpy(ozone->theme_dynamic.cursor_border, ozone->theme->cursor_border_0, sizeof(ozone->theme_dynamic.cursor_border)); + menu_animation_kill_by_tag(&tag); + + ozone_animate_cursor(ozone, ozone->theme_dynamic.cursor_border, ozone->theme->cursor_border_1); +} + +void ozone_draw_text( + video_frame_info_t *video_info, + ozone_handle_t *ozone, + const char *str, float x, + float y, + enum text_alignment text_align, + unsigned width, unsigned height, font_data_t* font, + uint32_t color, + bool draw_outside) +{ + if ((color & 0x000000FF) == 0) + return; + + menu_display_draw_text(font, str, x, y, + width, height, color, text_align, 1.0f, + false, + 1.0, draw_outside); +} + +static void ozone_draw_cursor_slice(ozone_handle_t *ozone, + video_frame_info_t *video_info, + int x_offset, + unsigned width, unsigned height, + size_t y, float alpha) +{ + ozone_color_alpha(ozone->theme_dynamic.cursor_alpha, alpha); + ozone_color_alpha(ozone->theme_dynamic.cursor_border, alpha); + + menu_display_blend_begin(video_info); + + /* Cursor without border */ + menu_display_draw_texture_slice( + video_info, + x_offset - 14, + y + 8, + 80, 80, + width + 3 + 28 - 4, + height + 20, + video_info->width, video_info->height, + ozone->theme_dynamic.cursor_alpha, + 20, 1.0, + ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_NO_BORDER] + ); + + /* Tainted border */ + menu_display_draw_texture_slice( + video_info, + x_offset - 14, + y + 8, + 80, 80, + width + 3 + 28 - 4, + height + 20, + video_info->width, video_info->height, + ozone->theme_dynamic.cursor_border, + 20, 1.0, + ozone->textures[OZONE_TEXTURE_CURSOR_BORDER] + ); + + menu_display_blend_end(video_info); +} + +static void ozone_draw_cursor_fallback(ozone_handle_t *ozone, + video_frame_info_t *video_info, + int x_offset, + unsigned width, unsigned height, + size_t y, float alpha) +{ + ozone_color_alpha(ozone->theme_dynamic.selection_border, alpha); + ozone_color_alpha(ozone->theme_dynamic.selection, alpha); + + /* Fill */ + menu_display_draw_quad(video_info, x_offset, y, width, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection); + + /* Borders (can't do one single quad because of alpha) */ + + /* Top */ + menu_display_draw_quad(video_info, x_offset - 3, y - 3, width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + + /* Bottom */ + menu_display_draw_quad(video_info, x_offset - 3, y + height - 5, width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + + /* Left */ + menu_display_draw_quad(video_info, x_offset - 3, y, 3, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + + /* Right */ + menu_display_draw_quad(video_info, x_offset + width, y, 3, height - 5, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); +} + +void ozone_draw_cursor(ozone_handle_t *ozone, + video_frame_info_t *video_info, + int x_offset, + unsigned width, unsigned height, + size_t y, float alpha) +{ + if (ozone->has_all_assets) + ozone_draw_cursor_slice(ozone, video_info, x_offset, width, height, y, alpha); + else + ozone_draw_cursor_fallback(ozone, video_info, x_offset, width, height, y, alpha); +} + +void ozone_color_alpha(float *color, float alpha) +{ + color[3] = color[7] = color[11] = color[15] = alpha; +} + +void ozone_draw_icon( + video_frame_info_t *video_info, + unsigned icon_width, + unsigned icon_height, + uintptr_t texture, + float x, float y, + unsigned width, unsigned height, + float rotation, float scale_factor, + float *color) +{ + menu_display_ctx_rotate_draw_t rotate_draw; + menu_display_ctx_draw_t draw; + struct video_coords coords; + math_matrix_4x4 mymat; + + rotate_draw.matrix = &mymat; + rotate_draw.rotation = rotation; + rotate_draw.scale_x = scale_factor; + rotate_draw.scale_y = scale_factor; + rotate_draw.scale_z = 1; + rotate_draw.scale_enable = true; + + menu_display_rotate_z(&rotate_draw, video_info); + + coords.vertices = 4; + coords.vertex = NULL; + coords.tex_coord = NULL; + coords.lut_tex_coord = NULL; + coords.color = color ? (const float*)color : ozone_pure_white; + + draw.x = x; + draw.y = height - y - icon_height; + draw.width = icon_width; + draw.height = icon_height; + draw.scale_factor = scale_factor; + draw.rotation = rotation; + draw.coords = &coords; + draw.matrix_data = &mymat; + draw.texture = texture; + draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP; + draw.pipeline.id = 0; + + menu_display_draw(&draw, video_info); +} + +void ozone_draw_backdrop(video_frame_info_t *video_info, float alpha) +{ + /* TODO Replace this backdrop by a blur shader on the whole screen if available */ + ozone_color_alpha(ozone_backdrop, alpha); + menu_display_draw_quad(video_info, 0, 0, video_info->width, video_info->height, video_info->width, video_info->height, ozone_backdrop); +} + +void ozone_draw_osk(ozone_handle_t *ozone, + video_frame_info_t *video_info, + const char *label, const char *str) +{ + int i; + const char *text; + char message[2048]; + unsigned text_color; + struct string_list *list; + + unsigned margin = 75; + unsigned padding = 10; + unsigned bottom_end = video_info->height/2; + unsigned y_offset = 0; + bool draw_placeholder = string_is_empty(str); + + retro_time_t current_time = cpu_features_get_time_usec(); + static retro_time_t last_time = 0; + + if (current_time - last_time >= INTERVAL_OSK_CURSOR) + { + ozone->osk_cursor = !ozone->osk_cursor; + last_time = current_time; + } + + /* Border */ + /* Top */ + menu_display_draw_quad(video_info, margin, margin, video_info->width - margin*2, 1, video_info->width, video_info->height, ozone->theme->entries_border); + + /* Bottom */ + menu_display_draw_quad(video_info, margin, bottom_end - margin, video_info->width - margin*2, 1, video_info->width, video_info->height, ozone->theme->entries_border); + + /* Left */ + menu_display_draw_quad(video_info, margin, margin, 1, bottom_end - margin*2, video_info->width, video_info->height, ozone->theme->entries_border); + + /* Right */ + menu_display_draw_quad(video_info, video_info->width - margin, margin, 1, bottom_end - margin*2, video_info->width, video_info->height, ozone->theme->entries_border); + + /* Backdrop */ + /* TODO Remove the backdrop if blur shader is available */ + menu_display_draw_quad(video_info, margin + 1, margin + 1, video_info->width - margin*2 - 2, bottom_end - margin*2 - 2, video_info->width, video_info->height, ozone_osk_backdrop); + + /* Placeholder & text*/ + if (!draw_placeholder) + { + text = str; + text_color = 0xffffffff; + } + else + { + text = label; + text_color = ozone_theme_light.text_sublabel_rgba; + } + + word_wrap(message, text, (video_info->width - margin*2 - padding*2) / ozone->entry_font_glyph_width, true); + + list = string_split(message, "\n"); + + for (i = 0; i < list->size; i++) + { + const char *msg = list->elems[i].data; + + ozone_draw_text(video_info, ozone, msg, margin + padding * 2, margin + padding + FONT_SIZE_ENTRIES_LABEL + y_offset, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, text_color, false); + + /* Cursor */ + if (i == list->size - 1) + { + if (ozone->osk_cursor) + { + unsigned cursor_x = draw_placeholder ? 0 : font_driver_get_message_width(ozone->fonts.entries_label, msg, (unsigned)strlen(msg), 1); + menu_display_draw_quad(video_info, margin + padding*2 + cursor_x, margin + padding + y_offset + 3, 1, 25, video_info->width, video_info->height, ozone_pure_white); + } + } + else + { + y_offset += 25; + } + } + + /* Keyboard */ + menu_display_draw_keyboard( + ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_STATIC], + ozone->fonts.entries_label, + video_info, + menu_event_get_osk_grid(), + menu_event_get_osk_ptr(), + ozone->theme->text_rgba); + + string_list_free(list); +} + +void ozone_draw_messagebox(ozone_handle_t *ozone, + video_frame_info_t *video_info, + const char *message) +{ + unsigned i, y_position; + int x, y, longest = 0, longest_width = 0; + float line_height = 0; + unsigned width = video_info->width; + unsigned height = video_info->height; + struct string_list *list = !string_is_empty(message) + ? string_split(message, "\n") : NULL; + + if (!list || !ozone || !ozone->fonts.footer) + { + if (list) + string_list_free(list); + return; + } + + if (list->elems == 0) + goto end; + + line_height = 25; + + y_position = height / 2; + if (menu_input_dialog_get_display_kb()) + y_position = height / 4; + + x = width / 2; + y = y_position - (list->size-1) * line_height / 2; + + /* find the longest line width */ + for (i = 0; i < list->size; i++) + { + const char *msg = list->elems[i].data; + int len = (int)utf8len(msg); + + if (len > longest) + { + longest = len; + longest_width = font_driver_get_message_width( + ozone->fonts.footer, msg, (unsigned)strlen(msg), 1); + } + } + + ozone_color_alpha(ozone->theme_dynamic.message_background, ozone->animations.messagebox_alpha); + + menu_display_blend_begin(video_info); + + if (ozone->has_all_assets) /* avoid drawing a black box if there's no assets */ + menu_display_draw_texture_slice( + video_info, + x - longest_width/2 - 48, + y + 16 - 48, + 256, 256, + longest_width + 48 * 2, + line_height * list->size + 48 * 2, + width, height, + ozone->theme_dynamic.message_background, + 16, 1.0, + ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE] + ); + + for (i = 0; i < list->size; i++) + { + const char *msg = list->elems[i].data; + + if (msg) + ozone_draw_text(video_info, ozone, + msg, + x - longest_width/2.0, + y + (i+0.75) * line_height, + TEXT_ALIGN_LEFT, + width, height, + ozone->fonts.footer, + COLOR_TEXT_ALPHA(ozone->theme->text_rgba, (uint32_t)(ozone->animations.messagebox_alpha*255.0f)), + false + ); + } + +end: + string_list_free(list); +} \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_display.h b/menu/drivers/ozone/ozone_display.h new file mode 100644 index 0000000000..4693a1d856 --- /dev/null +++ b/menu/drivers/ozone/ozone_display.h @@ -0,0 +1,62 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" + +#include "../../menu_driver.h" + +void ozone_draw_text( + video_frame_info_t *video_info, + ozone_handle_t *ozone, + const char *str, float x, + float y, + enum text_alignment text_align, + unsigned width, unsigned height, font_data_t* font, + uint32_t color, + bool draw_outside); + +void ozone_draw_cursor(ozone_handle_t *ozone, + video_frame_info_t *video_info, + int x_offset, + unsigned width, unsigned height, + size_t y, float alpha); + +void ozone_color_alpha(float *color, float alpha); + +void ozone_draw_icon( + video_frame_info_t *video_info, + unsigned icon_width, + unsigned icon_height, + uintptr_t texture, + float x, float y, + unsigned width, unsigned height, + float rotation, float scale_factor, + float *color); + +void ozone_restart_cursor_animation(ozone_handle_t *ozone); + +void ozone_draw_backdrop(video_frame_info_t *video_info, float alpha); + +void ozone_draw_osk(ozone_handle_t *ozone, + video_frame_info_t *video_info, + const char *label, const char *str); + +void ozone_draw_messagebox(ozone_handle_t *ozone, + video_frame_info_t *video_info, + const char *message); \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_entries.c b/menu/drivers/ozone/ozone_entries.c new file mode 100644 index 0000000000..bb166168d8 --- /dev/null +++ b/menu/drivers/ozone/ozone_entries.c @@ -0,0 +1,320 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" +#include "ozone_texture.h" +#include "ozone_display.h" + +#include +#include + +#include "../../menu_driver.h" +#include "../../menu_animation.h" + +static void ozone_draw_entry_value(ozone_handle_t *ozone, + video_frame_info_t *video_info, + char *value, + unsigned x, unsigned y, + uint32_t alpha_uint32, + menu_entry_t *entry) +{ + bool switch_is_on = true; + bool do_draw_text = false; + + if (!entry->checked && string_is_empty(value)) + return; + + /* check icon */ + if (entry->checked) + { + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 30, 30, ozone->theme->textures[OZONE_THEME_TEXTURE_CHECK], x - 20, y - 22, video_info->width, video_info->height, 0, 1, ozone->theme_dynamic.entries_checkmark); + menu_display_blend_end(video_info); + return; + } + + /* text value */ + if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || + (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))) + { + switch_is_on = false; + do_draw_text = false; + } + else if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || + (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)))) + { + switch_is_on = true; + do_draw_text = false; + } + else + { + if (!string_is_empty(entry->value)) + { + if ( + string_is_equal(entry->value, "...") || + string_is_equal(entry->value, "(PRESET)") || + string_is_equal(entry->value, "(SHADER)") || + string_is_equal(entry->value, "(COMP)") || + string_is_equal(entry->value, "(CORE)") || + string_is_equal(entry->value, "(MOVIE)") || + string_is_equal(entry->value, "(MUSIC)") || + string_is_equal(entry->value, "(DIR)") || + string_is_equal(entry->value, "(RDB)") || + string_is_equal(entry->value, "(CURSOR)")|| + string_is_equal(entry->value, "(CFILE)") || + string_is_equal(entry->value, "(FILE)") || + string_is_equal(entry->value, "(IMAGE)") + ) + { + return; + } + else + do_draw_text = true; + } + else + do_draw_text = true; + } + + if (do_draw_text) + { + ozone_draw_text(video_info, ozone, value, x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, COLOR_TEXT_ALPHA(ozone->theme->text_selected_rgba, alpha_uint32), false); + } + else + { + ozone_draw_text(video_info, ozone, (switch_is_on ? msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON) : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)), + x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, + COLOR_TEXT_ALPHA(switch_is_on ? ozone->theme->text_selected_rgba : ozone->theme->text_sublabel_rgba, alpha_uint32), false); + } +} + +void ozone_draw_entries(ozone_handle_t *ozone, video_frame_info_t *video_info, + unsigned selection, unsigned selection_old, + file_list_t *selection_buf, float alpha, float scroll_y, + bool is_playlist) +{ + bool old_list; + uint32_t alpha_uint32; + size_t i, y, entries_end; + float sidebar_offset, bottom_boundary, invert, alpha_anim; + unsigned video_info_height, video_info_width, entry_width, button_height; + int x_offset = 22; + size_t selection_y = 0; + size_t old_selection_y = 0; + + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + entries_end = file_list_get_size(selection_buf); + old_list = selection_buf == ozone->selection_buf_old; + y = ENTRIES_START_Y; + sidebar_offset = ozone->sidebar_offset / 2.0f; + entry_width = video_info->width - 548; + button_height = 52; /* height of the button (entry minus sublabel) */ + + video_driver_get_size(&video_info_width, &video_info_height); + + bottom_boundary = video_info_height - 87 - 78; + invert = (ozone->fade_direction) ? -1 : 1; + alpha_anim = old_list ? alpha : 1.0f - alpha; + + if (old_list) + alpha = 1.0f - alpha; + + if (alpha != 1.0f) + { + if (old_list) + x_offset += invert * -(alpha_anim * 120); /* left */ + else + x_offset += invert * (alpha_anim * 120); /* right */ + } + + x_offset += (int) sidebar_offset; + alpha_uint32 = (uint32_t)(alpha*255.0f); + + /* Borders layer */ + for (i = 0; i < entries_end; i++) + { + bool entry_selected = selection == i; + bool entry_old_selected = selection_old == i; + ozone_node_t *node = NULL; + if (entry_selected) + selection_y = y; + + if (entry_old_selected) + old_selection_y = y; + + node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + if (!node || ozone->empty_playlist) + goto border_iterate; + + if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) + goto border_iterate; + else if (y + scroll_y - node->height - 20 > bottom_boundary) + goto border_iterate; + + ozone_color_alpha(ozone->theme_dynamic.entries_border, alpha); + ozone_color_alpha(ozone->theme_dynamic.entries_checkmark, alpha); + + /* Borders */ + menu_display_draw_quad(video_info, x_offset + 456-3, y - 3 + scroll_y, entry_width + 10 - 3 -1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); + menu_display_draw_quad(video_info, x_offset + 456-3, y - 3 + button_height + scroll_y, entry_width + 10 - 3-1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); + +border_iterate: + y += node->height; + } + + /* Cursor(s) layer - current */ + if (!ozone->cursor_in_sidebar) + ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, button_height, selection_y + scroll_y, ozone->animations.cursor_alpha * alpha); + + /* Old*/ + if (!ozone->cursor_in_sidebar_old) + ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, button_height, old_selection_y + scroll_y, (1-ozone->animations.cursor_alpha) * alpha); + + /* Icons + text */ + y = ENTRIES_START_Y; + + if (old_list) + y += ozone->old_list_offset_y; + + for (i = 0; i < entries_end; i++) + { + menu_texture_item tex; + menu_entry_t entry; + menu_animation_ctx_ticker_t ticker; + char entry_value[255]; + char rich_label[255]; + char entry_value_ticker[255]; + char *sublabel_str; + ozone_node_t *node = NULL; + char *entry_rich_label = NULL; + bool entry_selected = false; + int text_offset = -40; + float *icon_color = NULL; + + entry_value[0] = '\0'; + entry_selected = selection == i; + node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, (unsigned)i, selection_buf, true); + menu_entry_get_value(&entry, entry_value, sizeof(entry_value)); + + if (!node) + continue; + + if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) + goto icons_iterate; + else if (y + scroll_y - node->height - 20 > bottom_boundary) + goto icons_iterate; + + /* Prepare text */ + entry_rich_label = menu_entry_get_rich_label(&entry); + + ticker.idx = ozone->frame_count / 20; + ticker.s = rich_label; + ticker.str = entry_rich_label; + ticker.selected = entry_selected && !ozone->cursor_in_sidebar; + ticker.len = (entry_width - 60 - text_offset) / ozone->entry_font_glyph_width; + + menu_animation_ticker(&ticker); + + if (ozone->empty_playlist) + { + unsigned text_width = font_driver_get_message_width(ozone->fonts.entries_label, rich_label, (unsigned)strlen(rich_label), 1); + x_offset = (video_info_width - 408 - 162)/2 - text_width/2; + y = video_info_height/2 - 60; + } + + sublabel_str = menu_entry_get_sublabel(&entry); + + if (node->wrap && sublabel_str) + word_wrap(sublabel_str, sublabel_str, (video_info->width - 548) / ozone->sublabel_font_glyph_width, false); + + /* Icon */ + tex = ozone_entries_icon_get_texture(ozone, entry.enum_idx, entry.type, entry_selected); + if (tex != ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING]) + { + uintptr_t texture = tex; + + /* Console specific icons */ + if (entry.type == FILE_TYPE_RPL_ENTRY && ozone->horizontal_list && ozone->categories_selection_ptr > ozone->system_tab_end) + { + ozone_node_t *sidebar_node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, ozone->categories_selection_ptr - ozone->system_tab_end-1); + + if (!sidebar_node || !sidebar_node->content_icon) + texture = tex; + else + texture = sidebar_node->content_icon; + } + + /* Cheevos badges should not be recolored */ + if (!( + (entry.type >= MENU_SETTINGS_CHEEVOS_START) && + (entry.type < MENU_SETTINGS_NETPLAY_ROOMS_START) + )) + { + icon_color = ozone->theme_dynamic.entries_icon; + } + else + { + icon_color = ozone_pure_white; + } + + ozone_color_alpha(icon_color, alpha); + + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 46, 46, texture, x_offset + 451+5+10, y + scroll_y, video_info->width, video_info->height, 0, 1, icon_color); + menu_display_blend_end(video_info); + + if (icon_color == ozone_pure_white) + ozone_color_alpha(icon_color, 1.0f); + + text_offset = 0; + } + + /* Draw text */ + ozone_draw_text(video_info, ozone, rich_label, text_offset + x_offset + 521, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, COLOR_TEXT_ALPHA(ozone->theme->text_rgba, alpha_uint32), false); + if (sublabel_str) + ozone_draw_text(video_info, ozone, sublabel_str, x_offset + 470, y + FONT_SIZE_ENTRIES_SUBLABEL + 80 - 20 - 3 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_sublabel, COLOR_TEXT_ALPHA(ozone->theme->text_sublabel_rgba, alpha_uint32), false); + + /* Value */ + ticker.idx = ozone->frame_count / 20; + ticker.s = entry_value_ticker; + ticker.str = entry_value; + ticker.selected = entry_selected && !ozone->cursor_in_sidebar; + ticker.len = (entry_width - 60 - ((int)utf8len(entry_rich_label) * ozone->entry_font_glyph_width)) / ozone->entry_font_glyph_width; + + menu_animation_ticker(&ticker); + ozone_draw_entry_value(ozone, video_info, entry_value_ticker, x_offset + 426 + entry_width, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y,alpha_uint32, &entry); + + free(entry_rich_label); + + if (sublabel_str) + free(sublabel_str); + +icons_iterate: + y += node->height; + menu_entry_free(&entry); + } + + /* Text layer */ + font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_label, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_sublabel, video_info); +} \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_sidebar.c b/menu/drivers/ozone/ozone_sidebar.c new file mode 100644 index 0000000000..aeb7c7163b --- /dev/null +++ b/menu/drivers/ozone/ozone_sidebar.c @@ -0,0 +1,654 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +/* TODO Fluid sidebar width ? */ + +#include "ozone.h" +#include "ozone_theme.h" +#include "ozone_display.h" +#include "ozone_sidebar.h" + +#include +#include +#include + +#include "../../menu_animation.h" + +#include "../../../configuration.h" + +enum msg_hash_enums ozone_system_tabs_value[OZONE_SYSTEM_TAB_LAST] = { + MENU_ENUM_LABEL_VALUE_MAIN_MENU, + MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + MENU_ENUM_LABEL_VALUE_HISTORY_TAB, + MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + MENU_ENUM_LABEL_VALUE_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_ENUM_LABEL_VALUE_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_ENUM_LABEL_VALUE_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, +#endif + MENU_ENUM_LABEL_VALUE_ADD_TAB +}; + +enum menu_settings_type ozone_system_tabs_type[OZONE_SYSTEM_TAB_LAST] = { + MENU_SETTINGS, + MENU_SETTINGS_TAB, + MENU_HISTORY_TAB, + MENU_FAVORITES_TAB, + MENU_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_NETPLAY_TAB, +#endif + MENU_ADD_TAB +}; + +enum msg_hash_enums ozone_system_tabs_idx[OZONE_SYSTEM_TAB_LAST] = { + MENU_ENUM_LABEL_MAIN_MENU, + MENU_ENUM_LABEL_SETTINGS_TAB, + MENU_ENUM_LABEL_HISTORY_TAB, + MENU_ENUM_LABEL_FAVORITES_TAB, + MENU_ENUM_LABEL_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_ENUM_LABEL_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_ENUM_LABEL_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_ENUM_LABEL_NETPLAY_TAB, +#endif + MENU_ENUM_LABEL_ADD_TAB +}; + +unsigned ozone_system_tabs_icons[OZONE_SYSTEM_TAB_LAST] = { + OZONE_TAB_TEXTURE_MAIN_MENU, + OZONE_TAB_TEXTURE_SETTINGS, + OZONE_TAB_TEXTURE_HISTORY, + OZONE_TAB_TEXTURE_FAVORITES, + OZONE_TAB_TEXTURE_MUSIC, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_TAB_TEXTURE_VIDEO, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_TAB_TEXTURE_IMAGE, +#endif +#ifdef HAVE_NETWORKING + OZONE_TAB_TEXTURE_NETWORK, +#endif + OZONE_TAB_TEXTURE_SCAN_CONTENT +}; + +void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info) +{ + size_t y; + unsigned i, sidebar_height; + char console_title[255]; + menu_animation_ctx_ticker_t ticker; + + unsigned selection_y = 0; + unsigned selection_old_y = 0; + unsigned horizontal_list_size = 0; + + if (!ozone->draw_sidebar) + return; + + if (ozone->horizontal_list) + horizontal_list_size = ozone->horizontal_list->size; + + menu_display_scissor_begin(video_info, 0, 87, 408, video_info->height - 87 - 78); + + /* Background */ + sidebar_height = video_info->height - 87 - 55 - 78; + + if (!video_info->libretro_running) + { + menu_display_draw_quad(video_info, ozone->sidebar_offset, 88, 408, 55/2, video_info->width, video_info->height, ozone->theme->sidebar_top_gradient); + menu_display_draw_quad(video_info, ozone->sidebar_offset, 88 + 55/2, 408, sidebar_height, video_info->width, video_info->height, ozone->theme->sidebar_background); + menu_display_draw_quad(video_info, ozone->sidebar_offset, 55*2 + sidebar_height, 408, 55/2 + 1, video_info->width, video_info->height, ozone->theme->sidebar_bottom_gradient); + } + + /* Tabs */ + /* y offset computation */ + y = ENTRIES_START_Y - 10; + for (i = 0; i < ozone->system_tab_end + horizontal_list_size + 1; i++) + { + if (i == ozone->categories_selection_ptr) + { + selection_y = y; + if (ozone->categories_selection_ptr > ozone->system_tab_end) + selection_y += 30; + } + + if (i == ozone->categories_active_idx_old) + { + selection_old_y = y; + if (ozone->categories_active_idx_old > ozone->system_tab_end) + selection_old_y += 30; + } + + y += 65; + } + + /* Cursor */ + if (ozone->cursor_in_sidebar) + ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408 - 81, 52, selection_y-8 + ozone->animations.scroll_y_sidebar, ozone->animations.cursor_alpha); + + if (ozone->cursor_in_sidebar_old) + ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408 - 81, 52, selection_old_y-8 + ozone->animations.scroll_y_sidebar, 1-ozone->animations.cursor_alpha); + + /* Menu tabs */ + y = ENTRIES_START_Y - 10; + menu_display_blend_begin(video_info); + + for (i = 0; i < ozone->system_tab_end+1; i++) + { + enum msg_hash_enums value_idx; + const char *title = NULL; + bool selected = (ozone->categories_selection_ptr == i); + unsigned icon = ozone_system_tabs_icons[ozone->tabs[i]]; + + /* Icon */ + ozone_draw_icon(video_info, 40, 40, ozone->tab_textures[icon], ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); + + value_idx = ozone_system_tabs_value[ozone->tabs[i]]; + title = msg_hash_to_str(value_idx); + + /* Text */ + ozone_draw_text(video_info, ozone, title, ozone->sidebar_offset + 115 - 10, y + FONT_SIZE_SIDEBAR + ozone->animations.scroll_y_sidebar, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.sidebar, (selected ? ozone->theme->text_selected_rgba : ozone->theme->text_rgba), true); + + y += 65; + } + + menu_display_blend_end(video_info); + + /* Console tabs */ + if (horizontal_list_size > 0) + { + menu_display_draw_quad(video_info, ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, 408-81, 1, video_info->width, video_info->height, ozone->theme->entries_border); + + y += 30; + + menu_display_blend_begin(video_info); + + for (i = 0; i < horizontal_list_size; i++) + { + bool selected = (ozone->categories_selection_ptr == ozone->system_tab_end + 1 + i); + + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(ozone->horizontal_list, i); + + if (!node) + goto console_iterate; + + /* Icon */ + ozone_draw_icon(video_info, 40, 40, node->icon, ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); + + /* Text */ + ticker.idx = ozone->frame_count / 20; + ticker.len = 19; + ticker.s = console_title; + ticker.selected = selected; + ticker.str = node->console_name; + + menu_animation_ticker(&ticker); + + ozone_draw_text(video_info, ozone, console_title, ozone->sidebar_offset + 115 - 10, y + FONT_SIZE_SIDEBAR + ozone->animations.scroll_y_sidebar, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.sidebar, (selected ? ozone->theme->text_selected_rgba : ozone->theme->text_rgba), true); + +console_iterate: + y += 65; + } + + menu_display_blend_end(video_info); + + } + + font_driver_flush(video_info->width, video_info->height, ozone->fonts.sidebar, video_info); + ozone->raster_blocks.sidebar.carr.coords.vertices = 0; + + menu_display_scissor_end(video_info); +} + +void ozone_go_to_sidebar(ozone_handle_t *ozone, uintptr_t tag) +{ + struct menu_animation_ctx_entry entry; + + ozone->selection_old = ozone->selection; + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + ozone->cursor_in_sidebar = true; + + /* Cursor animation */ + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +void ozone_leave_sidebar(ozone_handle_t *ozone, uintptr_t tag) +{ + struct menu_animation_ctx_entry entry; + + if (ozone->empty_playlist) + return; + + ozone->categories_active_idx_old = ozone->categories_selection_ptr; + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + ozone->cursor_in_sidebar = false; + + /* Cursor animation */ + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +unsigned ozone_get_selected_sidebar_y_position(ozone_handle_t *ozone) +{ + return ozone->categories_selection_ptr * 65 + (ozone->categories_selection_ptr > ozone->system_tab_end ? 30 : 0); +} + +unsigned ozone_get_sidebar_height(ozone_handle_t *ozone) +{ + return (ozone->system_tab_end + 1 + (ozone->horizontal_list ? ozone->horizontal_list->size : 0)) * 65 + + (ozone->horizontal_list && ozone->horizontal_list->size > 0 ? 30 : 0); +} + +void ozone_sidebar_goto(ozone_handle_t *ozone, unsigned new_selection) +{ + unsigned video_info_height; + + video_driver_get_size(NULL, &video_info_height); + + struct menu_animation_ctx_entry entry; + + menu_animation_ctx_tag tag = (uintptr_t)ozone; + + if (ozone->categories_selection_ptr != new_selection) + { + ozone->categories_active_idx_old = ozone->categories_selection_ptr; + ozone->categories_selection_ptr = new_selection; + + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + + menu_animation_kill_by_tag(&tag); + } + + /* Cursor animation */ + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + /* Scroll animation */ + float new_scroll = 0; + float selected_position_y = ozone_get_selected_sidebar_y_position(ozone); + float current_selection_middle_onscreen = ENTRIES_START_Y - 10 + ozone->animations.scroll_y_sidebar + selected_position_y + 65 / 2; + float bottom_boundary = video_info_height - 87 - 78; + float entries_middle = video_info_height/2; + float entries_height = ozone_get_sidebar_height(ozone); + + if (current_selection_middle_onscreen != entries_middle) + new_scroll = ozone->animations.scroll_y_sidebar - (current_selection_middle_onscreen - entries_middle); + + if (new_scroll + entries_height < bottom_boundary) + new_scroll = -(30 + entries_height - bottom_boundary); + + if (new_scroll > 0) + new_scroll = 0; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.scroll_y_sidebar; + entry.tag = tag; + entry.target_value = new_scroll; + entry.userdata = NULL; + + menu_animation_push(&entry); + + if (new_selection > ozone->system_tab_end) + { + ozone_change_tab(ozone, MENU_ENUM_LABEL_HORIZONTAL_MENU, MENU_SETTING_HORIZONTAL_MENU); + } + else + { + ozone_change_tab(ozone, ozone_system_tabs_idx[ozone->tabs[new_selection]], ozone_system_tabs_type[ozone->tabs[new_selection]]); + } +} + + +void ozone_change_tab(ozone_handle_t *ozone, + enum msg_hash_enums tab, + enum menu_settings_type type) +{ + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + size_t stack_size; + menu_ctx_list_t list_info; + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + size_t selection = menu_navigation_get_selection(); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)file_list_get_actiondata_at_offset(selection_buf, + selection) : NULL; + + list_info.type = MENU_LIST_HORIZONTAL; + list_info.action = MENU_ACTION_LEFT; + + stack_size = menu_stack->size; + + if (menu_stack->list[stack_size - 1].label) + free(menu_stack->list[stack_size - 1].label); + menu_stack->list[stack_size - 1].label = NULL; + + menu_stack->list[stack_size - 1].label = + strdup(msg_hash_to_str(tab)); + menu_stack->list[stack_size - 1].type = + type; + + menu_driver_list_cache(&list_info); + + if (cbs && cbs->action_content_list_switch) + cbs->action_content_list_switch(selection_buf, menu_stack, "", "", 0); +} + +void ozone_init_horizontal_list(ozone_handle_t *ozone) +{ + menu_displaylist_info_t info; + settings_t *settings = config_get_ptr(); + + menu_displaylist_info_init(&info); + + info.list = ozone->horizontal_list; + info.path = strdup( + settings->paths.directory_playlist); + info.label = strdup( + msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST)); + info.exts = strdup( + file_path_str(FILE_PATH_LPL_EXTENSION_NO_DOT)); + info.type_default = FILE_TYPE_PLAIN; + info.enum_idx = MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST; + + if (settings->bools.menu_content_show_playlists && !string_is_empty(info.path)) + { + if (menu_displaylist_ctl(DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL, &info)) + { + size_t i; + for (i = 0; i < ozone->horizontal_list->size; i++) + { + ozone_node_t *node = ozone_alloc_node(); + file_list_set_userdata(ozone->horizontal_list, i, node); + } + + menu_displaylist_process(&info); + } + } + + menu_displaylist_info_free(&info); +} + +void ozone_refresh_horizontal_list(ozone_handle_t *ozone) +{ + ozone_context_destroy_horizontal_list(ozone); + if (ozone->horizontal_list) + { + ozone_free_list_nodes(ozone->horizontal_list, false); + file_list_free(ozone->horizontal_list); + } + ozone->horizontal_list = NULL; + + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + + ozone->horizontal_list = (file_list_t*) + calloc(1, sizeof(file_list_t)); + + if (ozone->horizontal_list) + ozone_init_horizontal_list(ozone); + + ozone_context_reset_horizontal_list(ozone); +} + +void ozone_context_reset_horizontal_list(ozone_handle_t *ozone) +{ + unsigned i; + const char *title; + char title_noext[255]; + + size_t list_size = ozone_list_get_size(ozone, MENU_LIST_HORIZONTAL); + + for (i = 0; i < list_size; i++) + { + const char *path = NULL; + ozone_node_t *node = (ozone_node_t*)file_list_get_userdata_at_offset(ozone->horizontal_list, i); + + if (!node) + { + node = ozone_alloc_node(); + if (!node) + continue; + } + + file_list_get_at_offset(ozone->horizontal_list, i, + &path, NULL, NULL, NULL); + + if (!path) + continue; + + if (!strstr(path, file_path_str(FILE_PATH_LPL_EXTENSION))) + continue; + + { + struct texture_image ti; + char *sysname = (char*) + malloc(PATH_MAX_LENGTH * sizeof(char)); + char *texturepath = (char*) + malloc(PATH_MAX_LENGTH * sizeof(char)); + char *content_texturepath = (char*) + malloc(PATH_MAX_LENGTH * sizeof(char)); + char *icons_path = (char*) + malloc(PATH_MAX_LENGTH * sizeof(char)); + + strlcpy(icons_path, ozone->icons_path, PATH_MAX_LENGTH * sizeof(char)); + + sysname[0] = texturepath[0] = content_texturepath[0] = '\0'; + + fill_pathname_base_noext(sysname, path, + PATH_MAX_LENGTH * sizeof(char)); + + fill_pathname_join_concat(texturepath, icons_path, sysname, + file_path_str(FILE_PATH_PNG_EXTENSION), + PATH_MAX_LENGTH * sizeof(char)); + + /* If the playlist icon doesn't exist return default */ + + if (!filestream_exists(texturepath)) + fill_pathname_join_concat(texturepath, icons_path, "default", + file_path_str(FILE_PATH_PNG_EXTENSION), + PATH_MAX_LENGTH * sizeof(char)); + + ti.width = 0; + ti.height = 0; + ti.pixels = NULL; + ti.supports_rgba = video_driver_supports_rgba(); + + if (image_texture_load(&ti, texturepath)) + { + if(ti.pixels) + { + video_driver_texture_unload(&node->icon); + video_driver_texture_load(&ti, + TEXTURE_FILTER_MIPMAP_LINEAR, &node->icon); + } + + image_texture_free(&ti); + } + + fill_pathname_join_delim(sysname, sysname, + file_path_str(FILE_PATH_CONTENT_BASENAME), '-', + PATH_MAX_LENGTH * sizeof(char)); + strlcat(content_texturepath, icons_path, PATH_MAX_LENGTH * sizeof(char)); + + strlcat(content_texturepath, path_default_slash(), PATH_MAX_LENGTH * sizeof(char)); + strlcat(content_texturepath, sysname, PATH_MAX_LENGTH * sizeof(char)); + + /* If the content icon doesn't exist return default-content */ + if (!filestream_exists(content_texturepath)) + { + strlcat(icons_path, path_default_slash(), PATH_MAX_LENGTH * sizeof(char)); + strlcat(icons_path, "default", PATH_MAX_LENGTH * sizeof(char)); + fill_pathname_join_delim(content_texturepath, icons_path, + file_path_str(FILE_PATH_CONTENT_BASENAME), '-', + PATH_MAX_LENGTH * sizeof(char)); + } + + if (image_texture_load(&ti, content_texturepath)) + { + if(ti.pixels) + { + video_driver_texture_unload(&node->content_icon); + video_driver_texture_load(&ti, + TEXTURE_FILTER_MIPMAP_LINEAR, &node->content_icon); + } + + image_texture_free(&ti); + } + + /* Console name */ + menu_entries_get_at_offset( + ozone->horizontal_list, + i, + &title, NULL, NULL, NULL, NULL); + + fill_pathname_base_noext(title_noext, title, sizeof(title_noext)); + + /* Format : "Vendor - Console" + Remove everything before the hyphen + and the subsequent space */ + char *chr = title_noext; + bool hyphen_found = false; + + while (true) + { + if (*chr == '-') + { + hyphen_found = true; + break; + } + else if (*chr == '\0') + break; + + chr++; + } + + if (hyphen_found) + chr += 2; + else + chr = title_noext; + + node->console_name = strdup(chr); + + free(sysname); + free(texturepath); + free(content_texturepath); + free(icons_path); + } + } +} + +void ozone_context_destroy_horizontal_list(ozone_handle_t *ozone) +{ + unsigned i; + size_t list_size = ozone_list_get_size(ozone, MENU_LIST_HORIZONTAL); + + for (i = 0; i < list_size; i++) + { + const char *path = NULL; + ozone_node_t *node = (ozone_node_t*)file_list_get_userdata_at_offset(ozone->horizontal_list, i); + + if (!node) + continue; + + file_list_get_at_offset(ozone->horizontal_list, i, + &path, NULL, NULL, NULL); + + if (!path || !strstr(path, file_path_str(FILE_PATH_LPL_EXTENSION))) + continue; + + video_driver_texture_unload(&node->icon); + video_driver_texture_unload(&node->content_icon); + } +} + +bool ozone_is_playlist(ozone_handle_t *ozone) +{ + bool is_playlist; + + switch (ozone->categories_selection_ptr) + { + case OZONE_SYSTEM_TAB_MAIN: + case OZONE_SYSTEM_TAB_SETTINGS: + case OZONE_SYSTEM_TAB_ADD: + is_playlist = false; + break; + case OZONE_SYSTEM_TAB_HISTORY: + case OZONE_SYSTEM_TAB_FAVORITES: + case OZONE_SYSTEM_TAB_MUSIC: +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + case OZONE_SYSTEM_TAB_VIDEO: +#endif +#ifdef HAVE_IMAGEVIEWER + case OZONE_SYSTEM_TAB_IMAGES: +#endif +#ifdef HAVE_NETWORKING + case OZONE_SYSTEM_TAB_NETPLAY: +#endif + default: + is_playlist = true; + break; + } + + return is_playlist && ozone->depth == 1; +} \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_sidebar.h b/menu/drivers/ozone/ozone_sidebar.h new file mode 100644 index 0000000000..08c5aba2b8 --- /dev/null +++ b/menu/drivers/ozone/ozone_sidebar.h @@ -0,0 +1,55 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef _OZONE_SIDEBAR_H +#define _OZONE_SIDEBAR_H + +#include "ozone_texture.h" + +enum +{ + OZONE_SYSTEM_TAB_MAIN = 0, + OZONE_SYSTEM_TAB_SETTINGS, + OZONE_SYSTEM_TAB_HISTORY, + OZONE_SYSTEM_TAB_FAVORITES, + OZONE_SYSTEM_TAB_MUSIC, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_SYSTEM_TAB_VIDEO, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_SYSTEM_TAB_IMAGES, +#endif +#ifdef HAVE_NETWORKING + OZONE_SYSTEM_TAB_NETPLAY, +#endif + OZONE_SYSTEM_TAB_ADD, + + /* End of this enum - use the last one to determine num of possible tabs */ + OZONE_SYSTEM_TAB_LAST +}; + +extern enum msg_hash_enums ozone_system_tabs_value[OZONE_SYSTEM_TAB_LAST]; + +extern enum menu_settings_type ozone_system_tabs_type[OZONE_SYSTEM_TAB_LAST]; + +extern enum msg_hash_enums ozone_system_tabs_idx[OZONE_SYSTEM_TAB_LAST]; + +extern unsigned ozone_system_tabs_icons[OZONE_SYSTEM_TAB_LAST]; + +#endif \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c new file mode 100644 index 0000000000..7af3843ee1 --- /dev/null +++ b/menu/drivers/ozone/ozone_texture.c @@ -0,0 +1,841 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" +#include "ozone_texture.h" + +#include +#include + +#include "../../menu_driver.h" + +#include "../../../cheevos/badges.h" + +menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone, + enum msg_hash_enums enum_idx, unsigned type, bool active) +{ + switch (enum_idx) + { + case MENU_ENUM_LABEL_CORE_OPTIONS: + case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS]; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE]; + case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_UNDO]; + case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS]; + case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS]; + case MENU_ENUM_LABEL_DISK_OPTIONS: + case MENU_ENUM_LABEL_DISK_CYCLE_TRAY_STATUS: + case MENU_ENUM_LABEL_DISK_IMAGE_APPEND: + case MENU_ENUM_LABEL_DISK_INDEX: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS]; + case MENU_ENUM_LABEL_SHADER_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS]; + case MENU_ENUM_LABEL_ACHIEVEMENT_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST]; + case MENU_ENUM_LABEL_ACHIEVEMENT_LIST_HARDCORE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST]; + case MENU_ENUM_LABEL_SAVE_STATE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE]; + case MENU_ENUM_LABEL_LOAD_STATE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE]; + case MENU_ENUM_LABEL_PARENT_DIRECTORY: + case MENU_ENUM_LABEL_UNDO_LOAD_STATE: + case MENU_ENUM_LABEL_UNDO_SAVE_STATE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_UNDO]; + case MENU_ENUM_LABEL_TAKE_SCREENSHOT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT]; + case MENU_ENUM_LABEL_DELETE_ENTRY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE]; + case MENU_ENUM_LABEL_RESTART_CONTENT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; + case MENU_ENUM_LABEL_RENAME_ENTRY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RENAME]; + case MENU_ENUM_LABEL_RESUME_CONTENT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RESUME]; + case MENU_ENUM_LABEL_FAVORITES: + case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FOLDER]; + case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RDB]; + + + /* Menu collection submenus*/ + case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ZIP]; + case MENU_ENUM_LABEL_GOTO_FAVORITES: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE]; + case MENU_ENUM_LABEL_GOTO_IMAGES: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; + case MENU_ENUM_LABEL_GOTO_VIDEO: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIE]; + case MENU_ENUM_LABEL_GOTO_MUSIC: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSIC]; + + /* Menu icons */ + case MENU_ENUM_LABEL_CONTENT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_ASSETS: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: + case MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GAME: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU]; + case MENU_ENUM_LABEL_START_CORE: + case MENU_ENUM_LABEL_CHEAT_START_OR_CONT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RUN]; + case MENU_ENUM_LABEL_CORE_LIST: + case MENU_ENUM_LABEL_CORE_SETTINGS: + case MENU_ENUM_LABEL_CORE_UPDATER_LIST: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: + case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE]; + case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: + case MENU_ENUM_LABEL_SCAN_FILE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FILE]; + case MENU_ENUM_LABEL_ONLINE_UPDATER: + case MENU_ENUM_LABEL_UPDATER_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_UPDATER]; + case MENU_ENUM_LABEL_UPDATE_LAKKA: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU]; + case MENU_ENUM_LABEL_UPDATE_CHEATS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS]; + case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; + case MENU_ENUM_LABEL_UPDATE_OVERLAYS: + case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY]; + case MENU_ENUM_LABEL_UPDATE_CG_SHADERS: + case MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS: + case MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS: + case MENU_ENUM_LABEL_AUTO_SHADERS_ENABLE: + case MENU_ENUM_LABEL_VIDEO_SHADER_PARAMETERS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS]; + case MENU_ENUM_LABEL_INFORMATION: + case MENU_ENUM_LABEL_INFORMATION_LIST: + case MENU_ENUM_LABEL_SYSTEM_INFORMATION: + case MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INFO]; + case MENU_ENUM_LABEL_UPDATE_DATABASES: + case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RDB]; + case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CURSOR]; + case MENU_ENUM_LABEL_HELP_LIST: + case MENU_ENUM_LABEL_HELP_CONTROLS: + case MENU_ENUM_LABEL_HELP_LOADING_CONTENT: + case MENU_ENUM_LABEL_HELP_SCANNING_CONTENT: + case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: + case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: + case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_HELP]; + case MENU_ENUM_LABEL_QUIT_RETROARCH: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_EXIT]; + /* Settings icons*/ + case MENU_ENUM_LABEL_DRIVER_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS]; + case MENU_ENUM_LABEL_VIDEO_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_VIDEO]; + case MENU_ENUM_LABEL_AUDIO_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_AUDIO]; + case MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MIXER]; + case MENU_ENUM_LABEL_INPUT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES: + case MENU_ENUM_LABEL_INPUT_USER_1_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_2_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_3_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_4_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_5_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_6_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_7_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_8_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_9_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_10_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_11_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_12_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_13_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_14_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_15_BINDS: + case MENU_ENUM_LABEL_INPUT_USER_16_BINDS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS]; + case MENU_ENUM_LABEL_LATENCY_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LATENCY]; + case MENU_ENUM_LABEL_SAVING_SETTINGS: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG: + case MENU_ENUM_LABEL_SAVE_NEW_CONFIG: + case MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS: + case MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVING]; + case MENU_ENUM_LABEL_LOGGING_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LOG]; + case MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP]; + case MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING: + case MENU_ENUM_LABEL_RECORDING_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RECORD]; + case MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_STREAM]; + case MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING: + case MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING: + case MENU_ENUM_LABEL_CHEAT_DELETE_ALL: + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE: + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME: + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CONTENT_DIR: + case MENU_ENUM_LABEL_CORE_DELETE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE]; + case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OSD]; + case MENU_ENUM_LABEL_SHOW_WIMP: + case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_UI]; +#ifdef HAVE_LAKKA_SWITCH + case MENU_ENUM_LABEL_SWITCH_GPU_PROFILE: + case MENU_ENUM_LABEL_SWITCH_CPU_PROFILE: +#endif + case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_POWER]; + case MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS]; + case MENU_ENUM_LABEL_NETWORK_INFORMATION: + case MENU_ENUM_LABEL_NETWORK_SETTINGS: + case MENU_ENUM_LABEL_WIFI_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_NETWORK]; + case MENU_ENUM_LABEL_PLAYLIST_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST]; + case MENU_ENUM_LABEL_USER_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_USER]; + case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: + case MENU_ENUM_LABEL_SCAN_DIRECTORY: + case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FOLDER]; + case MENU_ENUM_LABEL_PRIVACY_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY]; + + case MENU_ENUM_LABEL_REWIND_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_REWIND]; + case MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE]; + case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS]; +#ifdef HAVE_NETWORKING + case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RUN]; + case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE]; + case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ROOM]; + case MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; +#endif + case MENU_ENUM_LABEL_REBOOT: + case MENU_ENUM_LABEL_RESET_TO_DEFAULT_CONFIG: + case MENU_ENUM_LABEL_CHEAT_RELOAD_CHEATS: + case MENU_ENUM_LABEL_RESTART_RETROARCH: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; + case MENU_ENUM_LABEL_SHUTDOWN: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN]; + case MENU_ENUM_LABEL_CONFIGURATIONS: + case MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS: + case MENU_ENUM_LABEL_REMAP_FILE_LOAD: + case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: + case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET: + case MENU_ENUM_LABEL_CHEAT_FILE_LOAD: + case MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE]; + case MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES: + case MENU_ENUM_LABEL_SHADER_APPLY_CHANGES: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK]; + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_AFTER: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_BEFORE: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_TOP: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_BOTTOM: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MENU_ADD]; + default: + break; + } + + switch(type) + { + case FILE_TYPE_DIRECTORY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FOLDER]; + case FILE_TYPE_PLAIN: + case FILE_TYPE_IN_CARCHIVE: + case FILE_TYPE_RPL_ENTRY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FILE]; + case FILE_TYPE_SHADER: + case FILE_TYPE_SHADER_PRESET: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS]; + case FILE_TYPE_CARCHIVE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ZIP]; + case FILE_TYPE_MUSIC: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSIC]; + case FILE_TYPE_IMAGE: + case FILE_TYPE_IMAGEVIEWER: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; + case FILE_TYPE_MOVIE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIE]; + case FILE_TYPE_CORE: + case FILE_TYPE_DIRECT_LOAD: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE]; + case FILE_TYPE_RDB: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RDB]; + case FILE_TYPE_CURSOR: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CURSOR]; + case FILE_TYPE_PLAYLIST_ENTRY: + case MENU_SETTING_ACTION_RUN: + case MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RESUME]; + case MENU_SETTING_ACTION_CLOSE: + case MENU_SETTING_ACTION_DELETE_ENTRY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE]; + case MENU_SETTING_ACTION_SAVESTATE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE]; + case MENU_SETTING_ACTION_LOADSTATE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE]; + case FILE_TYPE_RDB_ENTRY: + case MENU_SETTING_ACTION_CORE_INFORMATION: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO]; + case MENU_SETTING_ACTION_CORE_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS]; + case MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS]; + case MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS]; + case MENU_SETTING_ACTION_CORE_DISK_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS]; + case MENU_SETTING_ACTION_CORE_SHADER_OPTIONS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS]; + case MENU_SETTING_ACTION_SCREENSHOT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT]; + case MENU_SETTING_ACTION_RESET: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; + case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PAUSE]; + case MENU_SETTING_GROUP: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING]; +#ifdef HAVE_LAKKA_SWITCH + case MENU_SET_SWITCH_BRIGHTNESS: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_BRIGHTNESS]; +#endif + case MENU_INFO_MESSAGE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO]; + case MENU_WIFI: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_WIFI]; +#ifdef HAVE_NETWORKING + case MENU_ROOM: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ROOM]; + case MENU_ROOM_LAN: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN]; + case MENU_ROOM_RELAY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY]; +#endif + case MENU_SETTING_ACTION: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING]; + } + +#ifdef HAVE_CHEEVOS + if ( + (type >= MENU_SETTINGS_CHEEVOS_START) && + (type < MENU_SETTINGS_NETPLAY_ROOMS_START) + ) + { + int new_id = type - MENU_SETTINGS_CHEEVOS_START; + if (get_badge_texture(new_id) != 0) + return get_badge_texture(new_id); + /* Should be replaced with placeholder badge icon. */ + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS]; + } +#endif + + if ( + (type >= MENU_SETTINGS_INPUT_BEGIN) && + (type <= MENU_SETTINGS_INPUT_DESC_END) + ) + { + unsigned input_id; + if (type < MENU_SETTINGS_INPUT_DESC_BEGIN) + { + input_id = MENU_SETTINGS_INPUT_BEGIN; + if ( type == input_id + 2) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS]; + if ( type == input_id + 4) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; + if ( type == input_id + 5) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVING]; + input_id = input_id + 7; + } + else + { + input_id = MENU_SETTINGS_INPUT_DESC_BEGIN; + while (type > (input_id + 23)) + { + input_id = (input_id + 24) ; + } + } + if ( type == input_id ) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D]; + if ( type == (input_id + 1)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L]; + if ( type == (input_id + 2)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT]; + if ( type == (input_id + 3)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START]; + if ( type == (input_id + 4)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U]; + if ( type == (input_id + 5)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D]; + if ( type == (input_id + 6)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L]; + if ( type == (input_id + 7)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R]; + if ( type == (input_id + 8)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R]; + if ( type == (input_id + 9)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U]; + if ( type == (input_id + 10)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB]; + if ( type == (input_id + 11)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB]; + if ( type == (input_id + 12)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT]; + if ( type == (input_id + 13)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT]; + if ( type == (input_id + 14)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P]; + if ( type == (input_id + 15)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P]; + if ( type == (input_id + 16)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R]; + if ( type == (input_id + 17)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L]; + if ( type == (input_id + 18)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D]; + if ( type == (input_id + 19)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U]; + if ( type == (input_id + 20)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R]; + if ( type == (input_id + 21)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L]; + if ( type == (input_id + 22)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D]; + if ( type == (input_id + 23)) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U]; + } + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING]; +} + +const char *ozone_entries_icon_texture_path(ozone_handle_t *ozone, unsigned id) +{ + char icon_fullpath[255]; + char *icon_name = NULL; + +switch (id) + { + case OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU: +#if defined(HAVE_LAKKA) + icon_name = "lakka.png"; + break; +#else + icon_name = "retroarch.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS: + icon_name = "settings.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_HISTORY: + icon_name = "history.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES: + icon_name = "favorites.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE: + icon_name = "add-favorite.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MUSICS: + icon_name = "musics.png"; + break; +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + case OZONE_ENTRIES_ICONS_TEXTURE_MOVIES: + icon_name = "movies.png"; + break; +#endif +#ifdef HAVE_IMAGEVIEWER + case OZONE_ENTRIES_ICONS_TEXTURE_IMAGES: + icon_name = "images.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_SETTING: + icon_name = "setting.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING: + icon_name = "subsetting.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ARROW: + icon_name = "arrow.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RUN: + icon_name = "run.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CLOSE: + icon_name = "close.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RESUME: + icon_name = "resume.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CLOCK: + icon_name = "clock.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL: + icon_name = "battery-full.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING: + icon_name = "battery-charging.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_POINTER: + icon_name = "pointer.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE: + icon_name = "savestate.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE: + icon_name = "loadstate.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UNDO: + icon_name = "undo.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO: + icon_name = "core-infos.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_WIFI: + icon_name = "wifi.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS: + icon_name = "core-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS: + icon_name = "core-input-remapping-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS: + icon_name = "core-cheat-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS: + icon_name = "core-disk-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS: + icon_name = "core-shader-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST: + icon_name = "achievement-list.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT: + icon_name = "screenshot.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RELOAD: + icon_name = "reload.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RENAME: + icon_name = "rename.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FILE: + icon_name = "file.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FOLDER: + icon_name = "folder.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ZIP: + icon_name = "zip.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MUSIC: + icon_name = "music.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE: + icon_name = "favorites-content.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_IMAGE: + icon_name = "image.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MOVIE: + icon_name = "movie.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE: + icon_name = "core.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RDB: + icon_name = "database.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CURSOR: + icon_name = "cursor.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON: + icon_name = "on.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF: + icon_name = "off.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ADD: + icon_name = "add.png"; + break; +#ifdef HAVE_NETWORKING + case OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY: + icon_name = "netplay.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM: + icon_name = "menu_room.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN: + icon_name = "menu_room_lan.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY: + icon_name = "menu_room_relay.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_KEY: + icon_name = "key.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER: + icon_name = "key-hover.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE: + icon_name = "dialog-slice.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS: + icon_name = "menu_achievements.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_AUDIO: + icon_name = "menu_audio.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS: + icon_name = "menu_drivers.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_EXIT: + icon_name = "menu_exit.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP: + icon_name = "menu_frameskip.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_HELP: + icon_name = "menu_help.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INFO: + icon_name = "menu_info.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS: + icon_name = "Libretro - Pad.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LATENCY: + icon_name = "menu_latency.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_NETWORK: + icon_name = "menu_network.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_POWER: + icon_name = "menu_power.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RECORD: + icon_name = "menu_record.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SAVING: + icon_name = "menu_saving.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UPDATER: + icon_name = "menu_updater.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_VIDEO: + icon_name = "menu_video.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MIXER: + icon_name = "menu_mixer.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LOG: + icon_name = "menu_log.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OSD: + icon_name = "menu_osd.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UI: + icon_name = "menu_ui.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_USER: + icon_name = "menu_user.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY: + icon_name = "menu_privacy.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST: + icon_name = "menu_playlist.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU: + icon_name = "menu_quickmenu.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_REWIND: + icon_name = "menu_rewind.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY: + icon_name = "menu_overlay.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE: + icon_name = "menu_override.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS: + icon_name = "menu_notifications.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_STREAM: + icon_name = "menu_stream.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN: + icon_name = "menu_shutdown.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U: + icon_name = "input_DPAD-U.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D: + icon_name = "input_DPAD-D.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L: + icon_name = "input_DPAD-L.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R: + icon_name = "input_DPAD-R.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U: + icon_name = "input_STCK-U.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D: + icon_name = "input_STCK-D.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L: + icon_name = "input_STCK-L.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R: + icon_name = "input_STCK-R.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P: + icon_name = "input_STCK-P.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U: + icon_name = "input_BTN-U.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D: + icon_name = "input_BTN-D.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L: + icon_name = "input_BTN-L.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R: + icon_name = "input_BTN-R.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB: + icon_name = "input_LB.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB: + icon_name = "input_RB.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT: + icon_name = "input_LT.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT: + icon_name = "input_RT.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT: + icon_name = "input_SELECT.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START: + icon_name = "input_START.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK: + icon_name = "menu_check.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MENU_ADD: + icon_name = "menu_add.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_BRIGHTNESS: + icon_name = "menu_brightnes.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_PAUSE: + icon_name = "menu_pause.png"; + break; + } + + fill_pathname_join( + icon_fullpath, + ozone->icons_path, + icon_name, + sizeof(icon_fullpath) + ); + + if (!filestream_exists(icon_fullpath)) + { + return "subsetting.png"; + } + else + return icon_name; +} + +void ozone_unload_theme_textures(ozone_handle_t *ozone) +{ + int i; + int j; + + for (j = 0; j < ozone_themes_count; j++) + { + ozone_theme_t *theme = ozone_themes[j]; + for (i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) + video_driver_texture_unload(&theme->textures[i]); + } +} + +bool ozone_reset_theme_textures(ozone_handle_t *ozone) +{ + int i; + int j; + char theme_path[255]; + bool result = true; + + for (j = 0; j < ozone_themes_count; j++) + { + ozone_theme_t *theme = ozone_themes[j]; + + fill_pathname_join( + theme_path, + ozone->png_path, + theme->name, + sizeof(theme_path) + ); + + for (i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strlcpy(filename, OZONE_THEME_TEXTURES_FILES[i], sizeof(filename)); + strlcat(filename, ".png", sizeof(filename)); + + if (!menu_display_reset_textures_list(filename, theme_path, &theme->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + result = false; + } + } + + return result; +} \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_texture.h b/menu/drivers/ozone/ozone_texture.h new file mode 100644 index 0000000000..e06bea008f --- /dev/null +++ b/menu/drivers/ozone/ozone_texture.h @@ -0,0 +1,210 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef _OZONE_TEXTURE_H +#define _OZONE_TEXTURE_H + +#include "ozone.h" +#include "ozone_texture.h" + +#include "../../menu_driver.h" + +enum OZONE_TEXTURE { + OZONE_TEXTURE_RETROARCH = 0, + OZONE_TEXTURE_CURSOR_BORDER, + + OZONE_TEXTURE_LAST +}; + +static char *OZONE_TEXTURES_FILES[OZONE_TEXTURE_LAST] = { + "retroarch", + "cursor_border" +}; + +enum OZONE_THEME_TEXTURES { + OZONE_THEME_TEXTURE_BUTTON_A = 0, + OZONE_THEME_TEXTURE_BUTTON_B, + OZONE_THEME_TEXTURE_SWITCH, + OZONE_THEME_TEXTURE_CHECK, + + OZONE_THEME_TEXTURE_CURSOR_NO_BORDER, + OZONE_THEME_TEXTURE_CURSOR_STATIC, + + OZONE_THEME_TEXTURE_LAST +}; + +static char *OZONE_THEME_TEXTURES_FILES[OZONE_THEME_TEXTURE_LAST] = { + "button_a", + "button_b", + "switch", + "check", + "cursor_noborder", + "cursor_static" +}; + +enum OZONE_TAB_TEXTURES { + OZONE_TAB_TEXTURE_MAIN_MENU = 0, + OZONE_TAB_TEXTURE_SETTINGS, + OZONE_TAB_TEXTURE_HISTORY, + OZONE_TAB_TEXTURE_FAVORITES, + OZONE_TAB_TEXTURE_MUSIC, + OZONE_TAB_TEXTURE_VIDEO, + OZONE_TAB_TEXTURE_IMAGE, + OZONE_TAB_TEXTURE_NETWORK, + OZONE_TAB_TEXTURE_SCAN_CONTENT, + + OZONE_TAB_TEXTURE_LAST +}; + +static char *OZONE_TAB_TEXTURES_FILES[OZONE_TAB_TEXTURE_LAST] = { + "retroarch", + "settings", + "history", + "favorites", + "music", + "video", + "image", + "netplay", + "add" +}; + +enum +{ + OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU = 0, + OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS, + OZONE_ENTRIES_ICONS_TEXTURE_HISTORY, + OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES, + OZONE_ENTRIES_ICONS_TEXTURE_MUSICS, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_ENTRIES_ICONS_TEXTURE_MOVIES, +#endif +#ifdef HAVE_NETWORKING + OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_ENTRIES_ICONS_TEXTURE_IMAGES, +#endif + OZONE_ENTRIES_ICONS_TEXTURE_SETTING, + OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING, + OZONE_ENTRIES_ICONS_TEXTURE_ARROW, + OZONE_ENTRIES_ICONS_TEXTURE_RUN, + OZONE_ENTRIES_ICONS_TEXTURE_CLOSE, + OZONE_ENTRIES_ICONS_TEXTURE_RESUME, + OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE, + OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE, + OZONE_ENTRIES_ICONS_TEXTURE_UNDO, + OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO, + OZONE_ENTRIES_ICONS_TEXTURE_WIFI, + OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST, + OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT, + OZONE_ENTRIES_ICONS_TEXTURE_RELOAD, + OZONE_ENTRIES_ICONS_TEXTURE_RENAME, + OZONE_ENTRIES_ICONS_TEXTURE_FILE, + OZONE_ENTRIES_ICONS_TEXTURE_FOLDER, + OZONE_ENTRIES_ICONS_TEXTURE_ZIP, + OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE, + OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE, + OZONE_ENTRIES_ICONS_TEXTURE_MUSIC, + OZONE_ENTRIES_ICONS_TEXTURE_IMAGE, + OZONE_ENTRIES_ICONS_TEXTURE_MOVIE, + OZONE_ENTRIES_ICONS_TEXTURE_CORE, + OZONE_ENTRIES_ICONS_TEXTURE_RDB, + OZONE_ENTRIES_ICONS_TEXTURE_CURSOR, + OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON, + OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF, + OZONE_ENTRIES_ICONS_TEXTURE_CLOCK, + OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL, + OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING, + OZONE_ENTRIES_ICONS_TEXTURE_POINTER, + OZONE_ENTRIES_ICONS_TEXTURE_ADD, + OZONE_ENTRIES_ICONS_TEXTURE_KEY, + OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER, + OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE, + OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS, + OZONE_ENTRIES_ICONS_TEXTURE_AUDIO, + OZONE_ENTRIES_ICONS_TEXTURE_EXIT, + OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP, + OZONE_ENTRIES_ICONS_TEXTURE_INFO, + OZONE_ENTRIES_ICONS_TEXTURE_HELP, + OZONE_ENTRIES_ICONS_TEXTURE_NETWORK, + OZONE_ENTRIES_ICONS_TEXTURE_POWER, + OZONE_ENTRIES_ICONS_TEXTURE_SAVING, + OZONE_ENTRIES_ICONS_TEXTURE_UPDATER, + OZONE_ENTRIES_ICONS_TEXTURE_VIDEO, + OZONE_ENTRIES_ICONS_TEXTURE_RECORD, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS, + OZONE_ENTRIES_ICONS_TEXTURE_MIXER, + OZONE_ENTRIES_ICONS_TEXTURE_LOG, + OZONE_ENTRIES_ICONS_TEXTURE_OSD, + OZONE_ENTRIES_ICONS_TEXTURE_UI, + OZONE_ENTRIES_ICONS_TEXTURE_USER, + OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY, + OZONE_ENTRIES_ICONS_TEXTURE_LATENCY, + OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS, + OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST, + OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU, + OZONE_ENTRIES_ICONS_TEXTURE_REWIND, + OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY, + OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE, + OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS, + OZONE_ENTRIES_ICONS_TEXTURE_STREAM, + OZONE_ENTRIES_ICONS_TEXTURE_SHUTDOWN, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_U, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_D, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_L, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_DPAD_R, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_U, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_D, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_L, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_R, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_STCK_P, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SELECT, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_U, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_D, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_R, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LB, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RB, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_LT, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_RT, + OZONE_ENTRIES_ICONS_TEXTURE_CHECKMARK, + OZONE_ENTRIES_ICONS_TEXTURE_MENU_ADD, + OZONE_ENTRIES_ICONS_TEXTURE_BRIGHTNESS, + OZONE_ENTRIES_ICONS_TEXTURE_PAUSE, + OZONE_ENTRIES_ICONS_TEXTURE_LAST +}; + +const char *ozone_entries_icon_texture_path(ozone_handle_t *ozone, unsigned id); + +menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone, + enum msg_hash_enums enum_idx, unsigned type, bool active); + +bool ozone_reset_theme_textures(ozone_handle_t *ozone); +void ozone_unload_theme_textures(ozone_handle_t *ozone); + +#endif \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_theme.c b/menu/drivers/ozone/ozone_theme.c new file mode 100644 index 0000000000..fa9478fa82 --- /dev/null +++ b/menu/drivers/ozone/ozone_theme.c @@ -0,0 +1,136 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2018 - Daniel De Matteis + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "ozone.h" +#include "ozone_theme.h" +#include "ozone_display.h" + +ozone_theme_t ozone_theme_light = { + COLOR_HEX_TO_FLOAT(0xEBEBEB, 1.00), + ozone_background_libretro_running_light, + + COLOR_HEX_TO_FLOAT(0x2B2B2B, 1.00), + COLOR_HEX_TO_FLOAT(0x333333, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x10BEC5, 1.00), + COLOR_HEX_TO_FLOAT(0xCDCDCD, 1.00), + COLOR_HEX_TO_FLOAT(0x333333, 1.00), + COLOR_HEX_TO_FLOAT(0x374CFF, 1.00), + COLOR_HEX_TO_FLOAT(0xF0F0F0, 1.00), + + 0x333333FF, + 0x374CFFFF, + 0x878787FF, + + ozone_sidebar_background_light, + ozone_sidebar_gradient_top_light, + ozone_sidebar_gradient_bottom_light, + + ozone_border_0_light, + ozone_border_1_light, + + {0}, + + "light" +}; + +ozone_theme_t ozone_theme_dark = { + COLOR_HEX_TO_FLOAT(0x2D2D2D, 1.00), + ozone_background_libretro_running_dark, + + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x212227, 1.00), + COLOR_HEX_TO_FLOAT(0x2DA3CB, 1.00), + COLOR_HEX_TO_FLOAT(0x51514F, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x00D9AE, 1.00), + COLOR_HEX_TO_FLOAT(0x464646, 1.00), + + 0xFFFFFFFF, + 0x00FFC5FF, + 0x9F9FA1FF, + + ozone_sidebar_background_dark, + ozone_sidebar_gradient_top_dark, + ozone_sidebar_gradient_bottom_dark, + + ozone_border_0_dark, + ozone_border_1_dark, + + {0}, + + "dark" +}; + +ozone_theme_t *ozone_themes[] = { + &ozone_theme_light, + &ozone_theme_dark +}; + +unsigned ozone_themes_count = sizeof(ozone_themes) / sizeof(ozone_themes[0]); +unsigned last_color_theme = 0; +bool last_use_preferred_system_color_theme = false; +ozone_theme_t *ozone_default_theme = &ozone_theme_light; /* also used as a tag for cursor animation */ + +void ozone_set_color_theme(ozone_handle_t *ozone, unsigned color_theme) +{ + ozone_theme_t *theme = ozone_default_theme; + + if (!ozone) + return; + + switch (color_theme) + { + case 1: + theme = &ozone_theme_dark; + break; + case 0: + default: + break; + } + + ozone->theme = theme; + + memcpy(ozone->theme_dynamic.selection_border, ozone->theme->selection_border, sizeof(ozone->theme_dynamic.selection_border)); + memcpy(ozone->theme_dynamic.selection, ozone->theme->selection, sizeof(ozone->theme_dynamic.selection)); + memcpy(ozone->theme_dynamic.entries_border, ozone->theme->entries_border, sizeof(ozone->theme_dynamic.entries_border)); + memcpy(ozone->theme_dynamic.entries_icon, ozone->theme->entries_icon, sizeof(ozone->theme_dynamic.entries_icon)); + memcpy(ozone->theme_dynamic.entries_checkmark, ozone_pure_white, sizeof(ozone->theme_dynamic.entries_checkmark)); + memcpy(ozone->theme_dynamic.cursor_alpha, ozone_pure_white, sizeof(ozone->theme_dynamic.cursor_alpha)); + memcpy(ozone->theme_dynamic.message_background, ozone->theme->message_background, sizeof(ozone->theme_dynamic.message_background)); + + ozone_restart_cursor_animation(ozone); + + last_color_theme = color_theme; +} + +unsigned ozone_get_system_theme() +{ + unsigned ret = 0; +#ifdef HAVE_LIBNX + if (R_SUCCEEDED(setsysInitialize())) + { + ColorSetId theme; + setsysGetColorSetId(&theme); + ret = (theme == ColorSetId_Dark) ? 1 : 0; + setsysExit(); + } + + return ret; +#endif + return 0; +} \ No newline at end of file diff --git a/menu/drivers/ozone/ozone_theme.h b/menu/drivers/ozone/ozone_theme.h new file mode 100644 index 0000000000..09425e0dac --- /dev/null +++ b/menu/drivers/ozone/ozone_theme.h @@ -0,0 +1,171 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2018 - Daniel De Matteis + * Copyright (C) 2018 - natinusala + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef _OZONE_THEME_H +#define _OZONE_THEME_H + +#include "ozone.h" +#include "ozone_texture.h" + +#include "../../../retroarch.h" + +#define HEX_R(hex) ((hex >> 16) & 0xFF) * (1.0f / 255.0f) +#define HEX_G(hex) ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f) +#define HEX_B(hex) ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f) + +#define COLOR_HEX_TO_FLOAT(hex, alpha) { \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha \ +} + +#define COLOR_TEXT_ALPHA(color, alpha) (color & 0xFFFFFF00) | alpha + +static float ozone_pure_white[16] = { + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, +}; + +static float ozone_backdrop[16] = { + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, +}; + +static float ozone_osk_backdrop[16] = { + 0.00, 0.00, 0.00, 0.15, + 0.00, 0.00, 0.00, 0.15, + 0.00, 0.00, 0.00, 0.15, + 0.00, 0.00, 0.00, 0.15, +}; + +static float ozone_sidebar_background_light[16] = { + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, +}; + +static float ozone_sidebar_gradient_top_light[16] = { + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.922, 0.922, 0.922, 1.00, + 0.922, 0.922, 0.922, 1.00, +}; + +static float ozone_sidebar_gradient_bottom_light[16] = { + 0.922, 0.922, 0.922, 1.00, + 0.922, 0.922, 0.922, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, +}; + +static float ozone_sidebar_background_dark[16] = { + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, +}; + +static float ozone_sidebar_gradient_top_dark[16] = { + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.18, 0.18, 0.18, 1.00, + 0.18, 0.18, 0.18, 1.00, +}; + +static float ozone_sidebar_gradient_bottom_dark[16] = { + 0.18, 0.18, 0.18, 1.00, + 0.18, 0.18, 0.18, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, +}; + +static float ozone_border_0_light[16] = COLOR_HEX_TO_FLOAT(0x50EFD9, 1.00); +static float ozone_border_1_light[16] = COLOR_HEX_TO_FLOAT(0x0DB6D5, 1.00); + +static float ozone_border_0_dark[16] = COLOR_HEX_TO_FLOAT(0x198AC6, 1.00); +static float ozone_border_1_dark[16] = COLOR_HEX_TO_FLOAT(0x89F1F2, 1.00); + +static float ozone_background_libretro_running_light[16] = { + 0.690, 0.690, 0.690, 0.75, + 0.690, 0.690, 0.690, 0.75, + 0.922, 0.922, 0.922, 1.0, + 0.922, 0.922, 0.922, 1.0 +}; + +static float ozone_background_libretro_running_dark[16] = { + 0.176, 0.176, 0.176, 0.75, + 0.176, 0.176, 0.176, 0.75, + 0.178, 0.178, 0.178, 1.0, + 0.178, 0.178, 0.178, 1.0, +}; + +typedef struct ozone_theme +{ + /* Background color */ + float background[16]; + float *background_libretro_running; + + /* Float colors for quads and icons */ + float header_footer_separator[16]; + float text[16]; + float selection[16]; + float selection_border[16]; + float entries_border[16]; + float entries_icon[16]; + float text_selected[16]; + float message_background[16]; + + /* RGBA colors for text */ + uint32_t text_rgba; + uint32_t text_selected_rgba; + uint32_t text_sublabel_rgba; + + /* Sidebar color */ + float *sidebar_background; + float *sidebar_top_gradient; + float *sidebar_bottom_gradient; + + /* + Fancy cursor colors + */ + float *cursor_border_0; + float *cursor_border_1; + + menu_texture_item textures[OZONE_THEME_TEXTURE_LAST]; + + const char *name; +} ozone_theme_t; + +extern ozone_theme_t ozone_theme_light; +extern ozone_theme_t ozone_theme_dark; + +extern ozone_theme_t *ozone_themes[]; + +extern unsigned ozone_themes_count; +extern unsigned last_color_theme; +extern bool last_use_preferred_system_color_theme; +extern ozone_theme_t *ozone_default_theme; + +void ozone_set_color_theme(ozone_handle_t *ozone, unsigned color_theme); +unsigned ozone_get_system_theme(); + +#endif \ No newline at end of file diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 66e02c18d2..0d85039a14 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -201,6 +201,9 @@ enum XMB_TEXTURE_INPUT_LT, XMB_TEXTURE_INPUT_RT, XMB_TEXTURE_CHECKMARK, + XMB_TEXTURE_MENU_ADD, + XMB_TEXTURE_BRIGHTNESS, + XMB_TEXTURE_PAUSE, XMB_TEXTURE_LAST }; @@ -264,6 +267,7 @@ typedef struct xmb_handle float shadow_offset; float font_size; float font2_size; + float previous_scale_factor; float margins_screen_left; float margins_screen_top; @@ -2107,7 +2111,6 @@ static void xmb_context_reset_horizontal_list( } } - xmb_toggle_horizontal_list(xmb); } static void xmb_refresh_horizontal_list(xmb_handle_t *xmb) @@ -2129,6 +2132,7 @@ static void xmb_refresh_horizontal_list(xmb_handle_t *xmb) xmb_init_horizontal_list(xmb); xmb_context_reset_horizontal_list(xmb); + xmb_toggle_horizontal_list(xmb); } static int xmb_environ(enum menu_environ_cb type, void *data, void *userdata) @@ -2270,6 +2274,9 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: return xmb->textures.list[XMB_TEXTURE_CHEAT_OPTIONS]; case MENU_ENUM_LABEL_DISK_OPTIONS: + case MENU_ENUM_LABEL_DISK_CYCLE_TRAY_STATUS: + case MENU_ENUM_LABEL_DISK_IMAGE_APPEND: + case MENU_ENUM_LABEL_DISK_INDEX: return xmb->textures.list[XMB_TEXTURE_DISK_OPTIONS]; case MENU_ENUM_LABEL_SHADER_OPTIONS: return xmb->textures.list[XMB_TEXTURE_SHADER_OPTIONS]; @@ -2499,6 +2506,11 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES: case MENU_ENUM_LABEL_SHADER_APPLY_CHANGES: return xmb->textures.list[XMB_TEXTURE_CHECKMARK]; + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_AFTER: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_BEFORE: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_TOP: + case MENU_ENUM_LABEL_CHEAT_ADD_NEW_BOTTOM: + return xmb->textures.list[XMB_TEXTURE_MENU_ADD]; default: break; } @@ -2559,7 +2571,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case FILE_TYPE_PLAYLIST_ENTRY: case MENU_SETTING_ACTION_RUN: case MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS: - return xmb->textures.list[XMB_TEXTURE_RUN]; + return xmb->textures.list[XMB_TEXTURE_RESUME]; case MENU_SETTING_ACTION_CLOSE: case MENU_SETTING_ACTION_DELETE_ENTRY: return xmb->textures.list[XMB_TEXTURE_CLOSE]; @@ -2585,12 +2597,12 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_SETTING_ACTION_RESET: return xmb->textures.list[XMB_TEXTURE_RELOAD]; case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: - return xmb->textures.list[XMB_TEXTURE_RESUME]; - - case MENU_SETTING_GROUP: + return xmb->textures.list[XMB_TEXTURE_PAUSE]; #ifdef HAVE_LAKKA_SWITCH case MENU_SET_SWITCH_BRIGHTNESS: + return xmb->textures.list[XMB_TEXTURE_BRIGHTNESS]; #endif + case MENU_SETTING_GROUP: return xmb->textures.list[XMB_TEXTURE_SETTING]; case MENU_INFO_MESSAGE: return xmb->textures.list[XMB_TEXTURE_CORE_INFO]; @@ -3307,6 +3319,711 @@ static void xmb_draw_dark_layer( menu_display_blend_end(video_info); } +static const char *xmb_texture_path(unsigned id) +{ + char *iconpath = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); + char *icon_name = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); + char *icon_fullpath = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); + + iconpath[0] = icon_name[0] = icon_fullpath[0] = '\0'; + + switch (id) + { + case XMB_TEXTURE_MAIN_MENU: +#if defined(HAVE_LAKKA) + icon_name = "lakka.png"; + break; +#else + icon_name = "retroarch.png"; + break; +#endif + case XMB_TEXTURE_SETTINGS: + icon_name = "settings.png"; + break; + case XMB_TEXTURE_HISTORY: + icon_name = "history.png"; + break; + case XMB_TEXTURE_FAVORITES: + icon_name = "favorites.png"; + break; + case XMB_TEXTURE_ADD_FAVORITE: + icon_name = "add-favorite.png"; + break; + case XMB_TEXTURE_MUSICS: + icon_name = "musics.png"; + break; +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + case XMB_TEXTURE_MOVIES: + icon_name = "movies.png"; + break; +#endif +#ifdef HAVE_IMAGEVIEWER + case XMB_TEXTURE_IMAGES: + icon_name = "images.png"; + break; +#endif + case XMB_TEXTURE_SETTING: + icon_name = "setting.png"; + break; + case XMB_TEXTURE_SUBSETTING: + icon_name = "subsetting.png"; + break; + case XMB_TEXTURE_ARROW: + icon_name = "arrow.png"; + break; + case XMB_TEXTURE_RUN: + icon_name = "run.png"; + break; + case XMB_TEXTURE_CLOSE: + icon_name = "close.png"; + break; + case XMB_TEXTURE_RESUME: + icon_name = "resume.png"; + break; + case XMB_TEXTURE_CLOCK: + icon_name = "clock.png"; + break; + case XMB_TEXTURE_BATTERY_FULL: + icon_name = "battery-full.png"; + break; + case XMB_TEXTURE_BATTERY_CHARGING: + icon_name = "battery-charging.png"; + break; + case XMB_TEXTURE_POINTER: + icon_name = "pointer.png"; + break; + case XMB_TEXTURE_SAVESTATE: + icon_name = "savestate.png"; + break; + case XMB_TEXTURE_LOADSTATE: + icon_name = "loadstate.png"; + break; + case XMB_TEXTURE_UNDO: + icon_name = "undo.png"; + break; + case XMB_TEXTURE_CORE_INFO: + icon_name = "core-infos.png"; + break; + case XMB_TEXTURE_WIFI: + icon_name = "wifi.png"; + break; + case XMB_TEXTURE_CORE_OPTIONS: + icon_name = "core-options.png"; + break; + case XMB_TEXTURE_INPUT_REMAPPING_OPTIONS: + icon_name = "core-input-remapping-options.png"; + break; + case XMB_TEXTURE_CHEAT_OPTIONS: + icon_name = "core-cheat-options.png"; + break; + case XMB_TEXTURE_DISK_OPTIONS: + icon_name = "core-disk-options.png"; + break; + case XMB_TEXTURE_SHADER_OPTIONS: + icon_name = "core-shader-options.png"; + break; + case XMB_TEXTURE_ACHIEVEMENT_LIST: + icon_name = "achievement-list.png"; + break; + case XMB_TEXTURE_SCREENSHOT: + icon_name = "screenshot.png"; + break; + case XMB_TEXTURE_RELOAD: + icon_name = "reload.png"; + break; + case XMB_TEXTURE_RENAME: + icon_name = "rename.png"; + break; + case XMB_TEXTURE_FILE: + icon_name = "file.png"; + break; + case XMB_TEXTURE_FOLDER: + icon_name = "folder.png"; + break; + case XMB_TEXTURE_ZIP: + icon_name = "zip.png"; + break; + case XMB_TEXTURE_MUSIC: + icon_name = "music.png"; + break; + case XMB_TEXTURE_FAVORITE: + icon_name = "favorites-content.png"; + break; + case XMB_TEXTURE_IMAGE: + icon_name = "image.png"; + break; + case XMB_TEXTURE_MOVIE: + icon_name = "movie.png"; + break; + case XMB_TEXTURE_CORE: + icon_name = "core.png"; + break; + case XMB_TEXTURE_RDB: + icon_name = "database.png"; + break; + case XMB_TEXTURE_CURSOR: + icon_name = "cursor.png"; + break; + case XMB_TEXTURE_SWITCH_ON: + icon_name = "on.png"; + break; + case XMB_TEXTURE_SWITCH_OFF: + icon_name = "off.png"; + break; + case XMB_TEXTURE_ADD: + icon_name = "add.png"; + break; +#ifdef HAVE_NETWORKING + case XMB_TEXTURE_NETPLAY: + icon_name = "netplay.png"; + break; + case XMB_TEXTURE_ROOM: + icon_name = "menu_room.png"; + break; + case XMB_TEXTURE_ROOM_LAN: + icon_name = "menu_room_lan.png"; + break; + case XMB_TEXTURE_ROOM_RELAY: + icon_name = "menu_room_relay.png"; + break; +#endif + case XMB_TEXTURE_KEY: + icon_name = "key.png"; + break; + case XMB_TEXTURE_KEY_HOVER: + icon_name = "key-hover.png"; + break; + case XMB_TEXTURE_DIALOG_SLICE: + icon_name = "dialog-slice.png"; + break; + case XMB_TEXTURE_ACHIEVEMENTS: + icon_name = "menu_achievements.png"; + break; + case XMB_TEXTURE_AUDIO: + icon_name = "menu_audio.png"; + break; + case XMB_TEXTURE_DRIVERS: + icon_name = "menu_drivers.png"; + break; + case XMB_TEXTURE_EXIT: + icon_name = "menu_exit.png"; + break; + case XMB_TEXTURE_FRAMESKIP: + icon_name = "menu_frameskip.png"; + break; + case XMB_TEXTURE_HELP: + icon_name = "menu_help.png"; + break; + case XMB_TEXTURE_INFO: + icon_name = "menu_info.png"; + break; + case XMB_TEXTURE_INPUT_SETTINGS: + icon_name = "Libretro - Pad.png"; + break; + case XMB_TEXTURE_LATENCY: + icon_name = "menu_latency.png"; + break; + case XMB_TEXTURE_NETWORK: + icon_name = "menu_network.png"; + break; + case XMB_TEXTURE_POWER: + icon_name = "menu_power.png"; + break; + case XMB_TEXTURE_RECORD: + icon_name = "menu_record.png"; + break; + case XMB_TEXTURE_SAVING: + icon_name = "menu_saving.png"; + break; + case XMB_TEXTURE_UPDATER: + icon_name = "menu_updater.png"; + break; + case XMB_TEXTURE_VIDEO: + icon_name = "menu_video.png"; + break; + case XMB_TEXTURE_MIXER: + icon_name = "menu_mixer.png"; + break; + case XMB_TEXTURE_LOG: + icon_name = "menu_log.png"; + break; + case XMB_TEXTURE_OSD: + icon_name = "menu_osd.png"; + break; + case XMB_TEXTURE_UI: + icon_name = "menu_ui.png"; + break; + case XMB_TEXTURE_USER: + icon_name = "menu_user.png"; + break; + case XMB_TEXTURE_PRIVACY: + icon_name = "menu_privacy.png"; + break; + case XMB_TEXTURE_PLAYLIST: + icon_name = "menu_playlist.png"; + break; + case XMB_TEXTURE_QUICKMENU: + icon_name = "menu_quickmenu.png"; + break; + case XMB_TEXTURE_REWIND: + icon_name = "menu_rewind.png"; + break; + case XMB_TEXTURE_OVERLAY: + icon_name = "menu_overlay.png"; + break; + case XMB_TEXTURE_OVERRIDE: + icon_name = "menu_override.png"; + break; + case XMB_TEXTURE_NOTIFICATIONS: + icon_name = "menu_notifications.png"; + break; + case XMB_TEXTURE_STREAM: + icon_name = "menu_stream.png"; + break; + case XMB_TEXTURE_SHUTDOWN: + icon_name = "menu_shutdown.png"; + break; + case XMB_TEXTURE_INPUT_DPAD_U: + icon_name = "input_DPAD-U.png"; + break; + case XMB_TEXTURE_INPUT_DPAD_D: + icon_name = "input_DPAD-D.png"; + break; + case XMB_TEXTURE_INPUT_DPAD_L: + icon_name = "input_DPAD-L.png"; + break; + case XMB_TEXTURE_INPUT_DPAD_R: + icon_name = "input_DPAD-R.png"; + break; + case XMB_TEXTURE_INPUT_STCK_U: + icon_name = "input_STCK-U.png"; + break; + case XMB_TEXTURE_INPUT_STCK_D: + icon_name = "input_STCK-D.png"; + break; + case XMB_TEXTURE_INPUT_STCK_L: + icon_name = "input_STCK-L.png"; + break; + case XMB_TEXTURE_INPUT_STCK_R: + icon_name = "input_STCK-R.png"; + break; + case XMB_TEXTURE_INPUT_STCK_P: + icon_name = "input_STCK-P.png"; + break; + case XMB_TEXTURE_INPUT_BTN_U: + icon_name = "input_BTN-U.png"; + break; + case XMB_TEXTURE_INPUT_BTN_D: + icon_name = "input_BTN-D.png"; + break; + case XMB_TEXTURE_INPUT_BTN_L: + icon_name = "input_BTN-L.png"; + break; + case XMB_TEXTURE_INPUT_BTN_R: + icon_name = "input_BTN-R.png"; + break; + case XMB_TEXTURE_INPUT_LB: + icon_name = "input_LB.png"; + break; + case XMB_TEXTURE_INPUT_RB: + icon_name = "input_RB.png"; + break; + case XMB_TEXTURE_INPUT_LT: + icon_name = "input_LT.png"; + break; + case XMB_TEXTURE_INPUT_RT: + icon_name = "input_RT.png"; + break; + case XMB_TEXTURE_INPUT_SELECT: + icon_name = "input_SELECT.png"; + break; + case XMB_TEXTURE_INPUT_START: + icon_name = "input_START.png"; + break; + case XMB_TEXTURE_CHECKMARK: + icon_name = "menu_check.png"; + break; + case XMB_TEXTURE_MENU_ADD: + icon_name = "menu_add.png"; + break; + case XMB_TEXTURE_BRIGHTNESS: + icon_name = "menu_brightness.png"; + break; + case XMB_TEXTURE_PAUSE: + icon_name = "menu_pause.png"; + break; + } + + fill_pathname_application_special(iconpath, + PATH_MAX_LENGTH * sizeof(char), + APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS); + + icon_fullpath = iconpath; + strlcat(icon_fullpath, icon_name, PATH_MAX_LENGTH * sizeof(char)); + + if (!filestream_exists(icon_fullpath)) + { + RARCH_WARN("[XMB] Asset missing: %s\n", icon_fullpath); + return NULL; + } + else + return icon_name; + +} + +static void xmb_context_reset_textures_nodes(xmb_handle_t *xmb) +{ + xmb->main_menu_node.icon = xmb->textures.list[XMB_TEXTURE_MAIN_MENU]; + xmb->main_menu_node.alpha = xmb->categories_active_alpha; + xmb->main_menu_node.zoom = xmb->categories_active_zoom; + + xmb->settings_tab_node.icon = xmb->textures.list[XMB_TEXTURE_SETTINGS]; + xmb->settings_tab_node.alpha = xmb->categories_active_alpha; + xmb->settings_tab_node.zoom = xmb->categories_active_zoom; + + xmb->history_tab_node.icon = xmb->textures.list[XMB_TEXTURE_HISTORY]; + xmb->history_tab_node.alpha = xmb->categories_active_alpha; + xmb->history_tab_node.zoom = xmb->categories_active_zoom; + + xmb->favorites_tab_node.icon = xmb->textures.list[XMB_TEXTURE_FAVORITES]; + xmb->favorites_tab_node.alpha = xmb->categories_active_alpha; + xmb->favorites_tab_node.zoom = xmb->categories_active_zoom; + + xmb->music_tab_node.icon = xmb->textures.list[XMB_TEXTURE_MUSICS]; + xmb->music_tab_node.alpha = xmb->categories_active_alpha; + xmb->music_tab_node.zoom = xmb->categories_active_zoom; + +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + xmb->video_tab_node.icon = xmb->textures.list[XMB_TEXTURE_MOVIES]; + xmb->video_tab_node.alpha = xmb->categories_active_alpha; + xmb->video_tab_node.zoom = xmb->categories_active_zoom; +#endif + +#ifdef HAVE_IMAGEVIEWER + xmb->images_tab_node.icon = xmb->textures.list[XMB_TEXTURE_IMAGES]; + xmb->images_tab_node.alpha = xmb->categories_active_alpha; + xmb->images_tab_node.zoom = xmb->categories_active_zoom; +#endif + + xmb->add_tab_node.icon = xmb->textures.list[XMB_TEXTURE_ADD]; + xmb->add_tab_node.alpha = xmb->categories_active_alpha; + xmb->add_tab_node.zoom = xmb->categories_active_zoom; + +#ifdef HAVE_NETWORKING + xmb->netplay_tab_node.icon = xmb->textures.list[XMB_TEXTURE_NETPLAY]; + xmb->netplay_tab_node.alpha = xmb->categories_active_alpha; + xmb->netplay_tab_node.zoom = xmb->categories_active_zoom; +#endif +} + +static void xmb_context_reset_textures( + xmb_handle_t *xmb, const char *iconpath) +{ + unsigned i; + settings_t *settings = config_get_ptr(); + + for (i = 0; i < XMB_TEXTURE_LAST; i++) + { + if (xmb_texture_path(i) == NULL) + { + /* If the icon doesn't exist at least try to return the subsetting icon*/ + if (!(i == XMB_TEXTURE_DIALOG_SLICE || i == XMB_TEXTURE_KEY_HOVER || i == XMB_TEXTURE_KEY_HOVER)) + menu_display_reset_textures_list(xmb_texture_path(XMB_TEXTURE_SUBSETTING), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); + continue; + } + menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); + } + + /* Warn only if critical assets are missing, some themes are incomplete */ + if ( + ((xmb_texture_path(XMB_TEXTURE_SUBSETTING) == NULL)) && !(settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM) + ) + runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false); + + menu_display_allocate_white_texture(); + + +} + +static void xmb_context_reset_background(const char *iconpath) +{ + char *path = NULL; + settings_t *settings = config_get_ptr(); + const char *path_menu_wp = settings->paths.path_menu_wallpaper; + + if (!string_is_empty(path_menu_wp)) + path = strdup(path_menu_wp); + else if (!string_is_empty(iconpath)) + { + path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + path[0] = '\0'; + + fill_pathname_join(path, iconpath, "bg.png", + PATH_MAX_LENGTH * sizeof(char)); + } + + if (filestream_exists(path)) + task_push_image_load(path, + menu_display_handle_wallpaper_upload, NULL); + + if (path) + free(path); +} + +static void xmb_context_reset(void *data, bool is_threaded) +{ + xmb_handle_t *xmb = (xmb_handle_t*)data; + char *iconpath = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + + char bg_file_path[PATH_MAX_LENGTH] = {0}; + iconpath[0] = '\0'; + fill_pathname_application_special(iconpath, + PATH_MAX_LENGTH * sizeof(char), + APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS); + fill_pathname_application_special(bg_file_path, + sizeof(bg_file_path), APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_BG); + + if (!string_is_empty(bg_file_path)) + { + if (!string_is_empty(xmb->bg_file_path)) + free(xmb->bg_file_path); + xmb->bg_file_path = strdup(bg_file_path); + } + + xmb_context_reset_textures(xmb, iconpath); + xmb_context_reset_background(iconpath); + xmb_context_reset_horizontal_list(xmb); + + xmb->previous_scale_factor = 0.0; + + free(iconpath); +} + +static void xmb_layout_ps3(xmb_handle_t *xmb, int width) +{ + unsigned new_font_size, new_header_height; + settings_t *settings = config_get_ptr(); + + float scale_factor = + (settings->uints.menu_xmb_scale_factor * width) / (1920.0 * 100); + + xmb->above_subitem_offset = 1.5; + xmb->above_item_offset = -1.0; + xmb->active_item_factor = 3.0; + xmb->under_item_offset = 5.0; + + xmb->categories_active_zoom = 1.0; + xmb->categories_passive_zoom = 0.5; + xmb->items_active_zoom = 1.0; + xmb->items_passive_zoom = 0.5; + + xmb->categories_active_alpha = 1.0; + xmb->categories_passive_alpha = 0.85; + xmb->items_active_alpha = 1.0; + xmb->items_passive_alpha = 0.85; + + xmb->shadow_offset = 2.0; + + new_font_size = 32.0 * scale_factor; + xmb->font2_size = 24.0 * scale_factor; + new_header_height = 128.0 * scale_factor; + + + xmb->thumbnail_width = 1024.0 * scale_factor; + xmb->left_thumbnail_width = 1024.0 * scale_factor; + xmb->savestate_thumbnail_width= 460.0 * scale_factor; + xmb->cursor_size = 64.0 * scale_factor; + + xmb->icon_spacing_horizontal = 200.0 * scale_factor; + xmb->icon_spacing_vertical = 64.0 * scale_factor; + + xmb->margins_screen_top = (256+32) * scale_factor; + xmb->margins_screen_left = 336.0 * scale_factor; + + xmb->margins_title_left = 60 * scale_factor; + xmb->margins_title_top = 60 * scale_factor + new_font_size / 3; + xmb->margins_title_bottom = 60 * scale_factor - new_font_size / 3; + + xmb->margins_label_left = 85.0 * scale_factor; + xmb->margins_label_top = new_font_size / 3.0; + + xmb->margins_setting_left = 600.0 * scale_factor * scale_mod[6]; + xmb->margins_dialog = 48 * scale_factor; + + xmb->margins_slice = 16; + + xmb->icon_size = 128.0 * scale_factor; + xmb->font_size = new_font_size; + + menu_display_set_header_height(new_header_height); +} + +static void xmb_layout_psp(xmb_handle_t *xmb, int width) +{ + unsigned new_font_size, new_header_height; + settings_t *settings = config_get_ptr(); + float scale_factor = + ((settings->uints.menu_xmb_scale_factor * width) / (1920.0 * 100)) * 1.5; +#ifdef _3DS + scale_factor = + settings->uints.menu_xmb_scale_factor / 400.0; +#endif + + xmb->above_subitem_offset = 1.5; + xmb->above_item_offset = -1.0; + xmb->active_item_factor = 2.0; + xmb->under_item_offset = 3.0; + + xmb->categories_active_zoom = 1.0; + xmb->categories_passive_zoom = 1.0; + xmb->items_active_zoom = 1.0; + xmb->items_passive_zoom = 1.0; + + xmb->categories_active_alpha = 1.0; + xmb->categories_passive_alpha = 0.85; + xmb->items_active_alpha = 1.0; + xmb->items_passive_alpha = 0.85; + + xmb->shadow_offset = 1.0; + + new_font_size = 32.0 * scale_factor; + xmb->font2_size = 24.0 * scale_factor; + new_header_height = 128.0 * scale_factor; + xmb->margins_screen_top = (256+32) * scale_factor; + + xmb->thumbnail_width = 460.0 * scale_factor; + xmb->left_thumbnail_width = 400.0 * scale_factor; + xmb->savestate_thumbnail_width= 460.0 * scale_factor; + xmb->cursor_size = 64.0; + + xmb->icon_spacing_horizontal = 250.0 * scale_factor; + xmb->icon_spacing_vertical = 108.0 * scale_factor; + + xmb->margins_screen_left = 136.0 * scale_factor; + xmb->margins_title_left = 60 * scale_factor; + xmb->margins_title_top = 60 * scale_factor + new_font_size / 3; + xmb->margins_title_bottom = 60 * scale_factor - new_font_size / 3; + xmb->margins_label_left = 85.0 * scale_factor; + xmb->margins_label_top = new_font_size / 3.0; + xmb->margins_setting_left = 600.0 * scale_factor; + xmb->margins_dialog = 48 * scale_factor; + xmb->margins_slice = 16; + xmb->icon_size = 128.0 * scale_factor; + xmb->font_size = new_font_size; + + menu_display_set_header_height(new_header_height); +} + +static void xmb_layout(xmb_handle_t *xmb) +{ + unsigned width, height, i, current, end; + settings_t *settings = config_get_ptr(); + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + size_t selection = menu_navigation_get_selection(); + + video_driver_get_size(&width, &height); + + switch (settings->uints.menu_xmb_layout) + { + /* Automatic */ + case 0: + { + xmb->use_ps3_layout = false; + xmb->use_ps3_layout = width > 320 && height > 240; + + /* Mimic the layout of the PSP instead of the PS3 on tiny screens */ + if (xmb->use_ps3_layout) + xmb_layout_ps3(xmb, width); + else + xmb_layout_psp(xmb, width); + } + break; + /* PS3 */ + case 1: + { + xmb->use_ps3_layout = true; + xmb_layout_ps3(xmb, width); + } + break; + /* PSP */ + case 2: + { + xmb->use_ps3_layout = false; + xmb_layout_psp(xmb, width); + } + break; + } + +#ifdef XMB_DEBUG + RARCH_LOG("[XMB] margin screen left: %.2f\n", xmb->margins_screen_left); + RARCH_LOG("[XMB] margin screen top: %.2f\n", xmb->margins_screen_top); + RARCH_LOG("[XMB] margin title left: %.2f\n", xmb->margins_title_left); + RARCH_LOG("[XMB] margin title top: %.2f\n", xmb->margins_title_top); + RARCH_LOG("[XMB] margin title bott: %.2f\n", xmb->margins_title_bottom); + RARCH_LOG("[XMB] margin label left: %.2f\n", xmb->margins_label_left); + RARCH_LOG("[XMB] margin label top: %.2f\n", xmb->margins_label_top); + RARCH_LOG("[XMB] margin sett left: %.2f\n", xmb->margins_setting_left); + RARCH_LOG("[XMB] icon spacing hor: %.2f\n", xmb->icon_spacing_horizontal); + RARCH_LOG("[XMB] icon spacing ver: %.2f\n", xmb->icon_spacing_vertical); + RARCH_LOG("[XMB] icon size: %.2f\n", xmb->icon_size); +#endif + + current = (unsigned)selection; + end = (unsigned)menu_entries_get_size(); + + for (i = 0; i < end; i++) + { + float ia = xmb->items_passive_alpha; + float iz = xmb->items_passive_zoom; + xmb_node_t *node = (xmb_node_t*)file_list_get_userdata_at_offset( + selection_buf, i); + + if (!node) + continue; + + if (i == current) + { + ia = xmb->items_active_alpha; + iz = xmb->items_active_alpha; + } + + node->alpha = ia; + node->label_alpha = ia; + node->zoom = iz; + node->y = xmb_item_y(xmb, i, current); + } + + if (xmb->depth <= 1) + return; + + current = (unsigned)xmb->selection_ptr_old; + end = (unsigned)file_list_get_size(xmb->selection_buf_old); + + for (i = 0; i < end; i++) + { + float ia = 0; + float iz = xmb->items_passive_zoom; + xmb_node_t *node = (xmb_node_t*)file_list_get_userdata_at_offset( + xmb->selection_buf_old, i); + + if (!node) + continue; + + if (i == current) + { + ia = xmb->items_active_alpha; + iz = xmb->items_active_alpha; + } + + node->alpha = ia; + node->label_alpha = 0; + node->zoom = iz; + node->y = xmb_item_y(xmb, i, current); + node->x = xmb->icon_size * 1 * -2; + } +} + + static void xmb_frame(void *data, video_frame_info_t *video_info) { math_matrix_4x4 mymat; @@ -3336,6 +4053,38 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) scale_factor = (settings->uints.menu_xmb_scale_factor * (float)width) / (1920.0 * 100); pseudo_font_length = xmb->icon_spacing_horizontal * 4 - xmb->icon_size / 4; + if (scale_factor != xmb->previous_scale_factor) + { + bool video_is_threaded = video_driver_is_threaded(); + menu_display_font_free(xmb->font); + menu_display_font_free(xmb->font2); + xmb_layout(xmb); + xmb->font = menu_display_font( + APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT, + xmb->font_size, + video_is_threaded); + xmb->font2 = menu_display_font( + APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT, + xmb->font2_size, + video_is_threaded); + xmb_context_reset_textures_nodes(xmb); + xmb_toggle_horizontal_list(xmb); + + if (!string_is_equal(xmb_thumbnails_ident('R'), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + { + xmb_update_thumbnail_path(xmb, 0, 'R'); + xmb_update_thumbnail_image(xmb); + } + if (!string_is_equal(xmb_thumbnails_ident('L'), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + { + xmb_update_thumbnail_path(xmb, 0, 'L'); + xmb_update_thumbnail_image(xmb); + } + xmb_update_savestate_thumbnail_image(xmb); + } + xmb->frame_count++; msg[0] = '\0'; @@ -4085,230 +4834,8 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) } menu_display_unset_viewport(video_info->width, video_info->height); -} -static void xmb_layout_ps3(xmb_handle_t *xmb, int width) -{ - unsigned new_font_size, new_header_height; - settings_t *settings = config_get_ptr(); - - float scale_factor = - (settings->uints.menu_xmb_scale_factor * width) / (1920.0 * 100); - - xmb->above_subitem_offset = 1.5; - xmb->above_item_offset = -1.0; - xmb->active_item_factor = 3.0; - xmb->under_item_offset = 5.0; - - xmb->categories_active_zoom = 1.0; - xmb->categories_passive_zoom = 0.5; - xmb->items_active_zoom = 1.0; - xmb->items_passive_zoom = 0.5; - - xmb->categories_active_alpha = 1.0; - xmb->categories_passive_alpha = 0.85; - xmb->items_active_alpha = 1.0; - xmb->items_passive_alpha = 0.85; - - xmb->shadow_offset = 2.0; - - new_font_size = 32.0 * scale_factor; - xmb->font2_size = 24.0 * scale_factor; - new_header_height = 128.0 * scale_factor; - - - xmb->thumbnail_width = 1024.0 * scale_factor; - xmb->left_thumbnail_width = 1024.0 * scale_factor; - xmb->savestate_thumbnail_width= 460.0 * scale_factor; - xmb->cursor_size = 64.0 * scale_factor; - - xmb->icon_spacing_horizontal = 200.0 * scale_factor; - xmb->icon_spacing_vertical = 64.0 * scale_factor; - - xmb->margins_screen_top = (256+32) * scale_factor; - xmb->margins_screen_left = 336.0 * scale_factor; - - xmb->margins_title_left = 60 * scale_factor; - xmb->margins_title_top = 60 * scale_factor + new_font_size / 3; - xmb->margins_title_bottom = 60 * scale_factor - new_font_size / 3; - - xmb->margins_label_left = 85.0 * scale_factor; - xmb->margins_label_top = new_font_size / 3.0; - - xmb->margins_setting_left = 600.0 * scale_factor * scale_mod[6]; - xmb->margins_dialog = 48 * scale_factor; - - xmb->margins_slice = 16; - - xmb->icon_size = 128.0 * scale_factor; - xmb->font_size = new_font_size; - - menu_display_set_header_height(new_header_height); -} - -static void xmb_layout_psp(xmb_handle_t *xmb, int width) -{ - unsigned new_font_size, new_header_height; - settings_t *settings = config_get_ptr(); - float scale_factor = - ((settings->uints.menu_xmb_scale_factor * width) / (1920.0 * 100)) * 1.5; -#ifdef _3DS - scale_factor = - settings->uints.menu_xmb_scale_factor / 400.0; -#endif - - xmb->above_subitem_offset = 1.5; - xmb->above_item_offset = -1.0; - xmb->active_item_factor = 2.0; - xmb->under_item_offset = 3.0; - - xmb->categories_active_zoom = 1.0; - xmb->categories_passive_zoom = 1.0; - xmb->items_active_zoom = 1.0; - xmb->items_passive_zoom = 1.0; - - xmb->categories_active_alpha = 1.0; - xmb->categories_passive_alpha = 0.85; - xmb->items_active_alpha = 1.0; - xmb->items_passive_alpha = 0.85; - - xmb->shadow_offset = 1.0; - - new_font_size = 32.0 * scale_factor; - xmb->font2_size = 24.0 * scale_factor; - new_header_height = 128.0 * scale_factor; - xmb->margins_screen_top = (256+32) * scale_factor; - - xmb->thumbnail_width = 460.0 * scale_factor; - xmb->left_thumbnail_width = 400.0 * scale_factor; - xmb->savestate_thumbnail_width= 460.0 * scale_factor; - xmb->cursor_size = 64.0; - - xmb->icon_spacing_horizontal = 250.0 * scale_factor; - xmb->icon_spacing_vertical = 108.0 * scale_factor; - - xmb->margins_screen_left = 136.0 * scale_factor; - xmb->margins_title_left = 60 * scale_factor; - xmb->margins_title_top = 60 * scale_factor + new_font_size / 3; - xmb->margins_title_bottom = 60 * scale_factor - new_font_size / 3; - xmb->margins_label_left = 85.0 * scale_factor; - xmb->margins_label_top = new_font_size / 3.0; - xmb->margins_setting_left = 600.0 * scale_factor; - xmb->margins_dialog = 48 * scale_factor; - xmb->margins_slice = 16; - xmb->icon_size = 128.0 * scale_factor; - xmb->font_size = new_font_size; - - menu_display_set_header_height(new_header_height); -} - -static void xmb_layout(xmb_handle_t *xmb) -{ - unsigned width, height, i, current, end; - settings_t *settings = config_get_ptr(); - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - size_t selection = menu_navigation_get_selection(); - - video_driver_get_size(&width, &height); - - switch (settings->uints.menu_xmb_layout) - { - /* Automatic */ - case 0: - { - xmb->use_ps3_layout = false; - xmb->use_ps3_layout = width > 320 && height > 240; - - /* Mimic the layout of the PSP instead of the PS3 on tiny screens */ - if (xmb->use_ps3_layout) - xmb_layout_ps3(xmb, width); - else - xmb_layout_psp(xmb, width); - } - break; - /* PS3 */ - case 1: - { - xmb->use_ps3_layout = true; - xmb_layout_ps3(xmb, width); - } - break; - /* PSP */ - case 2: - { - xmb->use_ps3_layout = false; - xmb_layout_psp(xmb, width); - } - break; - } - -#ifdef XMB_DEBUG - RARCH_LOG("[XMB] margin screen left: %.2f\n", xmb->margins_screen_left); - RARCH_LOG("[XMB] margin screen top: %.2f\n", xmb->margins_screen_top); - RARCH_LOG("[XMB] margin title left: %.2f\n", xmb->margins_title_left); - RARCH_LOG("[XMB] margin title top: %.2f\n", xmb->margins_title_top); - RARCH_LOG("[XMB] margin title bott: %.2f\n", xmb->margins_title_bottom); - RARCH_LOG("[XMB] margin label left: %.2f\n", xmb->margins_label_left); - RARCH_LOG("[XMB] margin label top: %.2f\n", xmb->margins_label_top); - RARCH_LOG("[XMB] margin sett left: %.2f\n", xmb->margins_setting_left); - RARCH_LOG("[XMB] icon spacing hor: %.2f\n", xmb->icon_spacing_horizontal); - RARCH_LOG("[XMB] icon spacing ver: %.2f\n", xmb->icon_spacing_vertical); - RARCH_LOG("[XMB] icon size: %.2f\n", xmb->icon_size); -#endif - - current = (unsigned)selection; - end = (unsigned)menu_entries_get_size(); - - for (i = 0; i < end; i++) - { - float ia = xmb->items_passive_alpha; - float iz = xmb->items_passive_zoom; - xmb_node_t *node = (xmb_node_t*)file_list_get_userdata_at_offset( - selection_buf, i); - - if (!node) - continue; - - if (i == current) - { - ia = xmb->items_active_alpha; - iz = xmb->items_active_alpha; - } - - node->alpha = ia; - node->label_alpha = ia; - node->zoom = iz; - node->y = xmb_item_y(xmb, i, current); - } - - if (xmb->depth <= 1) - return; - - current = (unsigned)xmb->selection_ptr_old; - end = (unsigned)file_list_get_size(xmb->selection_buf_old); - - for (i = 0; i < end; i++) - { - float ia = 0; - float iz = xmb->items_passive_zoom; - xmb_node_t *node = (xmb_node_t*)file_list_get_userdata_at_offset( - xmb->selection_buf_old, i); - - if (!node) - continue; - - if (i == current) - { - ia = xmb->items_active_alpha; - iz = xmb->items_active_alpha; - } - - node->alpha = ia; - node->label_alpha = 0; - node->zoom = iz; - node->y = xmb_item_y(xmb, i, current); - node->x = xmb->icon_size * 1 * -2; - } + xmb->previous_scale_factor = scale_factor; } static void xmb_ribbon_set_vertex(float *ribbon_verts, @@ -4589,483 +5116,6 @@ static bool xmb_load_image(void *userdata, void *data, enum menu_image_type type return true; } -static const char *xmb_texture_path(unsigned id) -{ - char *iconpath = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); - char *icon_name = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); - char *icon_fullpath = (char*) malloc(PATH_MAX_LENGTH * sizeof(char)); - - iconpath[0] = icon_name[0] = icon_fullpath[0] = '\0'; - - switch (id) - { - case XMB_TEXTURE_MAIN_MENU: -#if defined(HAVE_LAKKA) - icon_name = "lakka.png"; - break; -#else - icon_name = "retroarch.png"; - break; -#endif - case XMB_TEXTURE_SETTINGS: - icon_name = "settings.png"; - break; - case XMB_TEXTURE_HISTORY: - icon_name = "history.png"; - break; - case XMB_TEXTURE_FAVORITES: - icon_name = "favorites.png"; - break; - case XMB_TEXTURE_ADD_FAVORITE: - icon_name = "add-favorite.png"; - break; - case XMB_TEXTURE_MUSICS: - icon_name = "musics.png"; - break; -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - case XMB_TEXTURE_MOVIES: - icon_name = "movies.png"; - break; -#endif -#ifdef HAVE_IMAGEVIEWER - case XMB_TEXTURE_IMAGES: - icon_name = "images.png"; - break; -#endif - case XMB_TEXTURE_SETTING: - icon_name = "setting.png"; - break; - case XMB_TEXTURE_SUBSETTING: - icon_name = "subsetting.png"; - break; - case XMB_TEXTURE_ARROW: - icon_name = "arrow.png"; - break; - case XMB_TEXTURE_RUN: - icon_name = "run.png"; - break; - case XMB_TEXTURE_CLOSE: - icon_name = "close.png"; - break; - case XMB_TEXTURE_RESUME: - icon_name = "resume.png"; - break; - case XMB_TEXTURE_CLOCK: - icon_name = "clock.png"; - break; - case XMB_TEXTURE_BATTERY_FULL: - icon_name = "battery-full.png"; - break; - case XMB_TEXTURE_BATTERY_CHARGING: - icon_name = "battery-charging.png"; - break; - case XMB_TEXTURE_POINTER: - icon_name = "pointer.png"; - break; - case XMB_TEXTURE_SAVESTATE: - icon_name = "savestate.png"; - break; - case XMB_TEXTURE_LOADSTATE: - icon_name = "loadstate.png"; - break; - case XMB_TEXTURE_UNDO: - icon_name = "undo.png"; - break; - case XMB_TEXTURE_CORE_INFO: - icon_name = "core-infos.png"; - break; - case XMB_TEXTURE_WIFI: - icon_name = "wifi.png"; - break; - case XMB_TEXTURE_CORE_OPTIONS: - icon_name = "core-options.png"; - break; - case XMB_TEXTURE_INPUT_REMAPPING_OPTIONS: - icon_name = "core-input-remapping-options.png"; - break; - case XMB_TEXTURE_CHEAT_OPTIONS: - icon_name = "core-cheat-options.png"; - break; - case XMB_TEXTURE_DISK_OPTIONS: - icon_name = "core-disk-options.png"; - break; - case XMB_TEXTURE_SHADER_OPTIONS: - icon_name = "core-shader-options.png"; - break; - case XMB_TEXTURE_ACHIEVEMENT_LIST: - icon_name = "achievement-list.png"; - break; - case XMB_TEXTURE_SCREENSHOT: - icon_name = "screenshot.png"; - break; - case XMB_TEXTURE_RELOAD: - icon_name = "reload.png"; - break; - case XMB_TEXTURE_RENAME: - icon_name = "rename.png"; - break; - case XMB_TEXTURE_FILE: - icon_name = "file.png"; - break; - case XMB_TEXTURE_FOLDER: - icon_name = "folder.png"; - break; - case XMB_TEXTURE_ZIP: - icon_name = "zip.png"; - break; - case XMB_TEXTURE_MUSIC: - icon_name = "music.png"; - break; - case XMB_TEXTURE_FAVORITE: - icon_name = "favorites-content.png"; - break; - case XMB_TEXTURE_IMAGE: - icon_name = "image.png"; - break; - case XMB_TEXTURE_MOVIE: - icon_name = "movie.png"; - break; - case XMB_TEXTURE_CORE: - icon_name = "core.png"; - break; - case XMB_TEXTURE_RDB: - icon_name = "database.png"; - break; - case XMB_TEXTURE_CURSOR: - icon_name = "cursor.png"; - break; - case XMB_TEXTURE_SWITCH_ON: - icon_name = "on.png"; - break; - case XMB_TEXTURE_SWITCH_OFF: - icon_name = "off.png"; - break; - case XMB_TEXTURE_ADD: - icon_name = "add.png"; - break; -#ifdef HAVE_NETWORKING - case XMB_TEXTURE_NETPLAY: - icon_name = "netplay.png"; - break; - case XMB_TEXTURE_ROOM: - icon_name = "menu_room.png"; - break; - case XMB_TEXTURE_ROOM_LAN: - icon_name = "menu_room_lan.png"; - break; - case XMB_TEXTURE_ROOM_RELAY: - icon_name = "menu_room_relay.png"; - break; -#endif - case XMB_TEXTURE_KEY: - icon_name = "key.png"; - break; - case XMB_TEXTURE_KEY_HOVER: - icon_name = "key-hover.png"; - break; - case XMB_TEXTURE_DIALOG_SLICE: - icon_name = "dialog-slice.png"; - break; - case XMB_TEXTURE_ACHIEVEMENTS: - icon_name = "menu_achievements.png"; - break; - case XMB_TEXTURE_AUDIO: - icon_name = "menu_audio.png"; - break; - case XMB_TEXTURE_DRIVERS: - icon_name = "menu_drivers.png"; - break; - case XMB_TEXTURE_EXIT: - icon_name = "menu_exit.png"; - break; - case XMB_TEXTURE_FRAMESKIP: - icon_name = "menu_frameskip.png"; - break; - case XMB_TEXTURE_HELP: - icon_name = "menu_help.png"; - break; - case XMB_TEXTURE_INFO: - icon_name = "menu_info.png"; - break; - case XMB_TEXTURE_INPUT_SETTINGS: - icon_name = "Libretro - Pad.png"; - break; - case XMB_TEXTURE_LATENCY: - icon_name = "menu_latency.png"; - break; - case XMB_TEXTURE_NETWORK: - icon_name = "menu_network.png"; - break; - case XMB_TEXTURE_POWER: - icon_name = "menu_power.png"; - break; - case XMB_TEXTURE_RECORD: - icon_name = "menu_record.png"; - break; - case XMB_TEXTURE_SAVING: - icon_name = "menu_saving.png"; - break; - case XMB_TEXTURE_UPDATER: - icon_name = "menu_updater.png"; - break; - case XMB_TEXTURE_VIDEO: - icon_name = "menu_video.png"; - break; - case XMB_TEXTURE_MIXER: - icon_name = "menu_mixer.png"; - break; - case XMB_TEXTURE_LOG: - icon_name = "menu_log.png"; - break; - case XMB_TEXTURE_OSD: - icon_name = "menu_osd.png"; - break; - case XMB_TEXTURE_UI: - icon_name = "menu_ui.png"; - break; - case XMB_TEXTURE_USER: - icon_name = "menu_user.png"; - break; - case XMB_TEXTURE_PRIVACY: - icon_name = "menu_privacy.png"; - break; - case XMB_TEXTURE_PLAYLIST: - icon_name = "menu_playlist.png"; - break; - case XMB_TEXTURE_QUICKMENU: - icon_name = "menu_quickmenu.png"; - break; - case XMB_TEXTURE_REWIND: - icon_name = "menu_rewind.png"; - break; - case XMB_TEXTURE_OVERLAY: - icon_name = "menu_overlay.png"; - break; - case XMB_TEXTURE_OVERRIDE: - icon_name = "menu_override.png"; - break; - case XMB_TEXTURE_NOTIFICATIONS: - icon_name = "menu_notifications.png"; - break; - case XMB_TEXTURE_STREAM: - icon_name = "menu_stream.png"; - break; - case XMB_TEXTURE_SHUTDOWN: - icon_name = "menu_shutdown.png"; - break; - case XMB_TEXTURE_INPUT_DPAD_U: - icon_name = "input_DPAD-U.png"; - break; - case XMB_TEXTURE_INPUT_DPAD_D: - icon_name = "input_DPAD-D.png"; - break; - case XMB_TEXTURE_INPUT_DPAD_L: - icon_name = "input_DPAD-L.png"; - break; - case XMB_TEXTURE_INPUT_DPAD_R: - icon_name = "input_DPAD-R.png"; - break; - case XMB_TEXTURE_INPUT_STCK_U: - icon_name = "input_STCK-U.png"; - break; - case XMB_TEXTURE_INPUT_STCK_D: - icon_name = "input_STCK-D.png"; - break; - case XMB_TEXTURE_INPUT_STCK_L: - icon_name = "input_STCK-L.png"; - break; - case XMB_TEXTURE_INPUT_STCK_R: - icon_name = "input_STCK-R.png"; - break; - case XMB_TEXTURE_INPUT_STCK_P: - icon_name = "input_STCK-P.png"; - break; - case XMB_TEXTURE_INPUT_BTN_U: - icon_name = "input_BTN-U.png"; - break; - case XMB_TEXTURE_INPUT_BTN_D: - icon_name = "input_BTN-D.png"; - break; - case XMB_TEXTURE_INPUT_BTN_L: - icon_name = "input_BTN-L.png"; - break; - case XMB_TEXTURE_INPUT_BTN_R: - icon_name = "input_BTN-R.png"; - break; - case XMB_TEXTURE_INPUT_LB: - icon_name = "input_LB.png"; - break; - case XMB_TEXTURE_INPUT_RB: - icon_name = "input_RB.png"; - break; - case XMB_TEXTURE_INPUT_LT: - icon_name = "input_LT.png"; - break; - case XMB_TEXTURE_INPUT_RT: - icon_name = "input_RT.png"; - break; - case XMB_TEXTURE_INPUT_SELECT: - icon_name = "input_SELECT.png"; - break; - case XMB_TEXTURE_INPUT_START: - icon_name = "input_START.png"; - break; - case XMB_TEXTURE_CHECKMARK: - icon_name = "menu_check.png"; - break; - } - - fill_pathname_application_special(iconpath, - PATH_MAX_LENGTH * sizeof(char), - APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS); - - icon_fullpath = iconpath; - strlcat(icon_fullpath, icon_name, PATH_MAX_LENGTH * sizeof(char)); - - if (!filestream_exists(icon_fullpath)) - { - /* If the icon doesn't exist at least try to return the subsetting icon*/ - if (id == XMB_TEXTURE_DIALOG_SLICE || id == XMB_TEXTURE_KEY_HOVER || id == XMB_TEXTURE_KEY_HOVER) - return NULL; - else - return "subsetting.png"; - } - else - return icon_name; - -} - -static void xmb_context_reset_textures( - xmb_handle_t *xmb, const char *iconpath) -{ - unsigned i; - - for (i = 0; i < XMB_TEXTURE_LAST; i++) - menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); - - menu_display_allocate_white_texture(); - - xmb->main_menu_node.icon = xmb->textures.list[XMB_TEXTURE_MAIN_MENU]; - xmb->main_menu_node.alpha = xmb->categories_active_alpha; - xmb->main_menu_node.zoom = xmb->categories_active_zoom; - - xmb->settings_tab_node.icon = xmb->textures.list[XMB_TEXTURE_SETTINGS]; - xmb->settings_tab_node.alpha = xmb->categories_active_alpha; - xmb->settings_tab_node.zoom = xmb->categories_active_zoom; - - xmb->history_tab_node.icon = xmb->textures.list[XMB_TEXTURE_HISTORY]; - xmb->history_tab_node.alpha = xmb->categories_active_alpha; - xmb->history_tab_node.zoom = xmb->categories_active_zoom; - - xmb->favorites_tab_node.icon = xmb->textures.list[XMB_TEXTURE_FAVORITES]; - xmb->favorites_tab_node.alpha = xmb->categories_active_alpha; - xmb->favorites_tab_node.zoom = xmb->categories_active_zoom; - - xmb->music_tab_node.icon = xmb->textures.list[XMB_TEXTURE_MUSICS]; - xmb->music_tab_node.alpha = xmb->categories_active_alpha; - xmb->music_tab_node.zoom = xmb->categories_active_zoom; - -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - xmb->video_tab_node.icon = xmb->textures.list[XMB_TEXTURE_MOVIES]; - xmb->video_tab_node.alpha = xmb->categories_active_alpha; - xmb->video_tab_node.zoom = xmb->categories_active_zoom; -#endif - -#ifdef HAVE_IMAGEVIEWER - xmb->images_tab_node.icon = xmb->textures.list[XMB_TEXTURE_IMAGES]; - xmb->images_tab_node.alpha = xmb->categories_active_alpha; - xmb->images_tab_node.zoom = xmb->categories_active_zoom; -#endif - - xmb->add_tab_node.icon = xmb->textures.list[XMB_TEXTURE_ADD]; - xmb->add_tab_node.alpha = xmb->categories_active_alpha; - xmb->add_tab_node.zoom = xmb->categories_active_zoom; - -#ifdef HAVE_NETWORKING - xmb->netplay_tab_node.icon = xmb->textures.list[XMB_TEXTURE_NETPLAY]; - xmb->netplay_tab_node.alpha = xmb->categories_active_alpha; - xmb->netplay_tab_node.zoom = xmb->categories_active_zoom; -#endif -} - -static void xmb_context_reset_background(const char *iconpath) -{ - char *path = NULL; - settings_t *settings = config_get_ptr(); - const char *path_menu_wp = settings->paths.path_menu_wallpaper; - - if (!string_is_empty(path_menu_wp)) - path = strdup(path_menu_wp); - else if (!string_is_empty(iconpath)) - { - path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); - path[0] = '\0'; - - fill_pathname_join(path, iconpath, "bg.png", - PATH_MAX_LENGTH * sizeof(char)); - } - - if (filestream_exists(path)) - task_push_image_load(path, - menu_display_handle_wallpaper_upload, NULL); - - if (path) - free(path); -} - -static void xmb_context_reset(void *data, bool is_threaded) -{ - xmb_handle_t *xmb = (xmb_handle_t*)data; - - if (xmb) - { - char bg_file_path[PATH_MAX_LENGTH] = {0}; - char *iconpath = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); - iconpath[0] = '\0'; - - fill_pathname_application_special(bg_file_path, - sizeof(bg_file_path), APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_BG); - - if (!string_is_empty(bg_file_path)) - { - if (!string_is_empty(xmb->bg_file_path)) - free(xmb->bg_file_path); - xmb->bg_file_path = strdup(bg_file_path); - } - - fill_pathname_application_special(iconpath, - PATH_MAX_LENGTH * sizeof(char), - APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS); - - xmb_layout(xmb); - xmb->font = menu_display_font(APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT, - xmb->font_size, - is_threaded); - xmb->font2 = menu_display_font(APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT, - xmb->font2_size, - is_threaded); - xmb_context_reset_textures(xmb, iconpath); - xmb_context_reset_background(iconpath); - xmb_context_reset_horizontal_list(xmb); - - if (!string_is_equal(xmb_thumbnails_ident('R'), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) - { - xmb_update_thumbnail_path(xmb, 0, 'R'); - xmb_update_thumbnail_image(xmb); - } - if (!string_is_equal(xmb_thumbnails_ident('L'), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) - { - xmb_update_thumbnail_path(xmb, 0, 'L'); - xmb_update_thumbnail_image(xmb); - } - xmb_update_savestate_thumbnail_image(xmb); - - free(iconpath); - } -} - static void xmb_navigation_clear(void *data, bool pending_push) { xmb_handle_t *xmb = (xmb_handle_t*)data; diff --git a/menu/menu_animation.c b/menu/menu_animation.c index d2b2b0f72f..559aa7e5bf 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -714,14 +714,13 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) void menu_timer_start(menu_timer_t *timer, menu_timer_ctx_entry_t *timer_entry) { + menu_animation_ctx_entry_t entry; menu_animation_ctx_tag tag = (uintptr_t) timer; menu_timer_kill(timer); *timer = 0.0f; - menu_animation_ctx_entry_t entry; - entry.easing_enum = EASING_LINEAR; entry.tag = tag; entry.duration = timer_entry->duration; diff --git a/menu/menu_cbs.h b/menu/menu_cbs.h index 1b69dffcd7..ed34b73021 100644 --- a/menu/menu_cbs.h +++ b/menu/menu_cbs.h @@ -45,6 +45,7 @@ enum ACTION_OK_DL_DEFAULT = 0, ACTION_OK_DL_DROPDOWN_BOX_LIST, ACTION_OK_DL_DROPDOWN_BOX_LIST_SPECIAL, + ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION, ACTION_OK_DL_OPEN_ARCHIVE, ACTION_OK_DL_OPEN_ARCHIVE_DETECT_CORE, ACTION_OK_DL_MUSIC, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index ac59ae52a7..5cfdbcdd8c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2014-2017 - Jean-André Santoni - * Copyright (C) 2015-2017 - Andrés Suárez + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -6546,9 +6546,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SUSPEND_SCREENSAVER_ENABLE, PARSE_ONLY_BOOL, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_SCREEN_RESOLUTION, - PARSE_ACTION, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PAL60_ENABLE, PARSE_ONLY_BOOL, false); @@ -6570,6 +6567,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_WINDOWED_FULLSCREEN, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SCREEN_RESOLUTION, + PARSE_ACTION, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_FULLSCREEN_X, PARSE_ONLY_UINT, false); @@ -6609,18 +6609,21 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_SCALE, PARSE_ONLY_FLOAT, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_VIDEO_WINDOW_WIDTH, - PARSE_ONLY_UINT, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_VIDEO_WINDOW_HEIGHT, - PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_WINDOW_OPACITY, PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_WINDOW_SHOW_DECORATIONS, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_VIDEO_WINDOW_SAVE_POSITION, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_VIDEO_WINDOW_WIDTH, + PARSE_ONLY_UINT, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_VIDEO_WINDOW_HEIGHT, + PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER, PARSE_ONLY_BOOL, false); @@ -8322,56 +8325,204 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist info->need_push = true; } break; - case DISPLAYLIST_DROPDOWN_LIST_SPECIAL: + case DISPLAYLIST_DROPDOWN_LIST_RESOLUTION: + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); { - menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + unsigned i, size = 0; + struct video_display_config *list = video_display_server_get_resolution_list(&size); - if (strstr(info->path, "core_option_")) + if (list) { - struct string_list *tmp_str_list = string_split(info->path, "_"); - - if (tmp_str_list && tmp_str_list->size > 0) + for (i = 0; i < size; i++) { - core_option_manager_t *coreopts = NULL; + char val_d[256], str[256]; + snprintf(str, sizeof(str), "%dx%d (%d Hz)", list[i].width, list[i].height, list[i].refreshrate); + snprintf(val_d, sizeof(val_d), "%d", i); + menu_entries_append_enum(info->list, + str, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + MENU_SETTING_DROPDOWN_ITEM_RESOLUTION, list[i].idx, 0); - rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts); + if (list[i].current) + menu_entries_set_checked(info->list, i, true); + } - if (coreopts) + free(list); + } + else + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0); + + } + info->need_refresh = true; + info->need_push = true; + break; + case DISPLAYLIST_DROPDOWN_LIST_SPECIAL: + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + if (strstr(info->path, "core_option_")) + { + struct string_list *tmp_str_list = string_split(info->path, "_"); + + if (tmp_str_list && tmp_str_list->size > 0) + { + core_option_manager_t *coreopts = NULL; + + rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts); + + if (coreopts) + { + unsigned size = (unsigned)tmp_str_list->size; + unsigned i = atoi(tmp_str_list->elems[size-1].data); + struct core_option *option = NULL; + bool checked_found = false; + unsigned checked = 0; + const char *val = core_option_manager_get_val(coreopts, i-1); + + i--; + + option = (struct core_option*)&coreopts->opts[i]; + + if (option) { - unsigned size = (unsigned)tmp_str_list->size; - unsigned i = atoi(tmp_str_list->elems[size-1].data); - struct core_option *option = NULL; - bool checked_found = false; - unsigned checked = 0; - const char *val = core_option_manager_get_val(coreopts, i-1); - - i--; - - option = (struct core_option*)&coreopts->opts[i]; - - if (option) + unsigned k; + for (k = 0; k < option->vals->size; k++) { - unsigned k; - for (k = 0; k < option->vals->size; k++) - { - const char *str = option->vals->elems[k].data; + const char *str = option->vals->elems[k].data; - if (!string_is_empty(str)) + if (!string_is_empty(str)) + { + char val_d[256]; + snprintf(val_d, sizeof(val_d), "%d", i); + menu_entries_append_enum(info->list, + str, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM_SPECIAL, k, 0); + + if (!checked_found && string_is_equal(str, val)) + { + checked = k; + checked_found = true; + } + + count++; + } + } + + if (checked_found) + menu_entries_set_checked(info->list, checked, true); + } + } + } + + } + else + { + enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info->path); + rarch_setting_t *setting = menu_setting_find_enum(enum_idx); + + if (setting) + { + switch (setting->type) + { + case ST_STRING_OPTIONS: + { + struct string_list *tmp_str_list = string_split(setting->values, "|"); + + if (tmp_str_list && tmp_str_list->size > 0) + { + unsigned i; + unsigned size = (unsigned)tmp_str_list->size; + bool checked_found = false; + unsigned checked = 0; + + for (i = 0; i < size; i++) { char val_d[256]; - snprintf(val_d, sizeof(val_d), "%d", i); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); menu_entries_append_enum(info->list, - str, + tmp_str_list->elems[i].data, val_d, MENU_ENUM_LABEL_NO_ITEMS, - MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM_SPECIAL, k, 0); + MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM_SPECIAL, i, 0); - if (!checked_found && string_is_equal(str, val)) + if (!checked_found && string_is_equal(tmp_str_list->elems[i].data, setting->value.target.string)) { - checked = k; + checked = i; checked_found = true; } + } + if (checked_found) + menu_entries_set_checked(info->list, checked, true); + } + } + break; + case ST_INT: + { + float i; + int32_t orig_value = *setting->value.target.integer; + unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_INT_ITEM_SPECIAL; + float step = setting->step; + double min = setting->enforce_minrange ? setting->min : 0.00; + double max = setting->enforce_maxrange ? setting->max : 999.00; + bool checked_found = false; + unsigned checked = 0; + + if (setting->get_string_representation) + { + for (i = min; i <= max; i += step) + { + char val_s[256], val_d[256]; + int val = (int)i; + + *setting->value.target.integer = val; + + setting->get_string_representation(setting, + val_s, sizeof(val_s)); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, val, 0); + + if (!checked_found && val == orig_value) + { + checked = count; + checked_found = true; + } + count++; + } + + *setting->value.target.integer = orig_value; + } + else + { + for (i = min; i <= max; i += step) + { + char val_s[16], val_d[16]; + int val = (int)i; + + snprintf(val_s, sizeof(val_s), "%d", val); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, val, 0); + + if (!checked_found && val == orig_value) + { + checked = count; + checked_found = true; + } count++; } } @@ -8379,263 +8530,149 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist if (checked_found) menu_entries_set_checked(info->list, checked, true); } - } - } + break; + case ST_FLOAT: + { + float i; + float orig_value = *setting->value.target.fraction; + unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM_SPECIAL; + float step = setting->step; + double min = setting->enforce_minrange ? setting->min : 0.00; + double max = setting->enforce_maxrange ? setting->max : 999.00; + bool checked_found = false; + unsigned checked = 0; - } - else - { - enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info->path); - rarch_setting_t *setting = menu_setting_find_enum(enum_idx); - - if (setting) - { - switch (setting->type) - { - case ST_STRING_OPTIONS: + if (setting->get_string_representation) { - struct string_list *tmp_str_list = string_split(setting->values, "|"); - - if (tmp_str_list && tmp_str_list->size > 0) + for (i = min; i <= max; i += step) { - unsigned i; - unsigned size = (unsigned)tmp_str_list->size; - bool checked_found = false; - unsigned checked = 0; + char val_s[256], val_d[256]; - for (i = 0; i < size; i++) + *setting->value.target.fraction = i; + + setting->get_string_representation(setting, + val_s, sizeof(val_s)); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, 0, 0); + + if (!checked_found && fabs(i - orig_value) <= 0.01f) { - char val_d[256]; - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - menu_entries_append_enum(info->list, - tmp_str_list->elems[i].data, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM_SPECIAL, i, 0); - - if (!checked_found && string_is_equal(tmp_str_list->elems[i].data, setting->value.target.string)) - { - checked = i; - checked_found = true; - } + checked = count; + checked_found = true; } + count++; + } - if (checked_found) - menu_entries_set_checked(info->list, checked, true); + *setting->value.target.fraction = orig_value; + } + else + { + for (i = min; i <= max; i += step) + { + char val_s[16], val_d[16]; + + snprintf(val_s, sizeof(val_s), "%.2f", i); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, 0, 0); + + if (!checked_found && fabs(i - orig_value) <= 0.01f) + { + checked = count; + checked_found = true; + } + count++; } } - break; - case ST_INT: + + if (checked_found) + menu_entries_set_checked(info->list, checked, true); + } + break; + case ST_UINT: + { + float i; + unsigned orig_value = *setting->value.target.unsigned_integer; + unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM_SPECIAL; + float step = setting->step; + double min = setting->enforce_minrange ? setting->min : 0.00; + double max = setting->enforce_maxrange ? setting->max : 999.00; + bool checked_found = false; + unsigned checked = 0; + + if (setting->get_string_representation) { - float i; - int32_t orig_value = *setting->value.target.integer; - unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_INT_ITEM_SPECIAL; - float step = setting->step; - double min = setting->enforce_minrange ? setting->min : 0.00; - double max = setting->enforce_maxrange ? setting->max : 999.00; - bool checked_found = false; - unsigned checked = 0; - - if (setting->get_string_representation) + for (i = min; i <= max; i += step) { - for (i = min; i <= max; i += step) + char val_s[256], val_d[256]; + int val = (int)i; + + *setting->value.target.unsigned_integer = val; + + setting->get_string_representation(setting, + val_s, sizeof(val_s)); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, val, 0); + + if (!checked_found && val == orig_value) { - char val_s[256], val_d[256]; - int val = (int)i; - - *setting->value.target.integer = val; - - setting->get_string_representation(setting, - val_s, sizeof(val_s)); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, val, 0); - - if (!checked_found && val == orig_value) - { - checked = count; - checked_found = true; - } - count++; - } - - *setting->value.target.integer = orig_value; - } - else - { - for (i = min; i <= max; i += step) - { - char val_s[16], val_d[16]; - int val = (int)i; - - snprintf(val_s, sizeof(val_s), "%d", val); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, val, 0); - - if (!checked_found && val == orig_value) - { - checked = count; - checked_found = true; - } - count++; + checked = count; + checked_found = true; } + count++; } - if (checked_found) - menu_entries_set_checked(info->list, checked, true); + *setting->value.target.unsigned_integer = orig_value; } - break; - case ST_FLOAT: + else { - float i; - float orig_value = *setting->value.target.fraction; - unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM_SPECIAL; - float step = setting->step; - double min = setting->enforce_minrange ? setting->min : 0.00; - double max = setting->enforce_maxrange ? setting->max : 999.00; - bool checked_found = false; - unsigned checked = 0; - - if (setting->get_string_representation) + for (i = min; i <= max; i += step) { - for (i = min; i <= max; i += step) + char val_s[16], val_d[16]; + int val = (int)i; + + snprintf(val_s, sizeof(val_s), "%d", val); + snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); + + menu_entries_append_enum(info->list, + val_s, + val_d, + MENU_ENUM_LABEL_NO_ITEMS, + setting_type, val, 0); + + if (!checked_found && val == orig_value) { - char val_s[256], val_d[256]; - - *setting->value.target.fraction = i; - - setting->get_string_representation(setting, - val_s, sizeof(val_s)); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, 0, 0); - - if (!checked_found && fabs(i - orig_value) <= 0.01f) - { - checked = count; - checked_found = true; - } - count++; + checked = count; + checked_found = true; } - - *setting->value.target.fraction = orig_value; + count++; } - else - { - for (i = min; i <= max; i += step) - { - char val_s[16], val_d[16]; - - snprintf(val_s, sizeof(val_s), "%.2f", i); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, 0, 0); - - if (!checked_found && fabs(i - orig_value) <= 0.01f) - { - checked = count; - checked_found = true; - } - count++; - } - } - - if (checked_found) - menu_entries_set_checked(info->list, checked, true); } - break; - case ST_UINT: - { - float i; - unsigned orig_value = *setting->value.target.unsigned_integer; - unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM_SPECIAL; - float step = setting->step; - double min = setting->enforce_minrange ? setting->min : 0.00; - double max = setting->enforce_maxrange ? setting->max : 999.00; - bool checked_found = false; - unsigned checked = 0; - if (setting->get_string_representation) - { - for (i = min; i <= max; i += step) - { - char val_s[256], val_d[256]; - int val = (int)i; - - *setting->value.target.unsigned_integer = val; - - setting->get_string_representation(setting, - val_s, sizeof(val_s)); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, val, 0); - - if (!checked_found && val == orig_value) - { - checked = count; - checked_found = true; - } - count++; - } - - *setting->value.target.unsigned_integer = orig_value; - } - else - { - for (i = min; i <= max; i += step) - { - char val_s[16], val_d[16]; - int val = (int)i; - - snprintf(val_s, sizeof(val_s), "%d", val); - snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx); - - menu_entries_append_enum(info->list, - val_s, - val_d, - MENU_ENUM_LABEL_NO_ITEMS, - setting_type, val, 0); - - if (!checked_found && val == orig_value) - { - checked = count; - checked_found = true; - } - count++; - } - } - - if (checked_found) - menu_entries_set_checked(info->list, checked, true); - } - break; - default: - break; - } + if (checked_found) + menu_entries_set_checked(info->list, checked, true); + } + break; + default: + break; } } - - info->need_refresh = true; - info->need_push = true; } + + info->need_refresh = true; + info->need_push = true; break; case DISPLAYLIST_NONE: break; diff --git a/menu/menu_displaylist.h b/menu/menu_displaylist.h index 79b8603dbd..a2a71f2af2 100644 --- a/menu/menu_displaylist.h +++ b/menu/menu_displaylist.h @@ -56,6 +56,7 @@ enum menu_displaylist_ctl_state DISPLAYLIST_NONE = 0, DISPLAYLIST_DROPDOWN_LIST, DISPLAYLIST_DROPDOWN_LIST_SPECIAL, + DISPLAYLIST_DROPDOWN_LIST_RESOLUTION, DISPLAYLIST_INFO, DISPLAYLIST_HELP, DISPLAYLIST_HELP_SCREEN_LIST, diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 25fc929b50..0e97b73a3f 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -143,6 +143,7 @@ enum menu_settings_type MENU_ADD_TAB, MENU_PLAYLISTS_TAB, MENU_SETTING_DROPDOWN_ITEM, + MENU_SETTING_DROPDOWN_ITEM_RESOLUTION, MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM, MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM, MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index b7af68fac5..1d76dedf57 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -5381,6 +5381,14 @@ static bool setting_append_list( CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_SCREEN_RESOLUTION, + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + &group_info, + &subgroup_info, + parent_group); + CONFIG_UINT( list, list_info, &custom_vp->width, @@ -5449,10 +5457,10 @@ static bool setting_append_list( settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); CONFIG_UINT( list, list_info, - &settings->uints.video_window_x, + &settings->uints.window_position_width, MENU_ENUM_LABEL_VIDEO_WINDOW_WIDTH, MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, - 0, + window_width, &group_info, &subgroup_info, parent_group, @@ -5463,10 +5471,10 @@ static bool setting_append_list( settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); CONFIG_UINT( list, list_info, - &settings->uints.video_window_y, + &settings->uints.window_position_height, MENU_ENUM_LABEL_VIDEO_WINDOW_HEIGHT, MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - 0, + window_height, &group_info, &subgroup_info, parent_group, @@ -5508,6 +5516,21 @@ static bool setting_append_list( SD_FLAG_NONE); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_REINIT); + CONFIG_BOOL( + list, list_info, + &settings->bools.video_window_save_positions, + MENU_ENUM_LABEL_VIDEO_WINDOW_SAVE_POSITION, + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SAVE_POSITION, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + CONFIG_BOOL( list, list_info, &settings->bools.video_scale_integer, diff --git a/msg_hash.h b/msg_hash.h index c343242314..e457eb3c30 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -421,6 +421,8 @@ enum msg_hash_enums MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, + MSG_MISSING_ASSETS, + MENU_LABEL(STREAMING_TITLE), MENU_LABEL(STREAMING_MODE), MENU_LABEL(VIDEO_RECORD_QUALITY), @@ -1013,6 +1015,7 @@ enum msg_hash_enums /* Deferred */ MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL, + MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION, MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_CONFIGURATIONS_LIST, MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST, @@ -1938,6 +1941,7 @@ enum msg_hash_enums MENU_LABEL(NETPLAY_USE_MITM_SERVER), MENU_LABEL(NETPLAY_MITM_SERVER), MENU_LABEL(VIDEO_WINDOW_SHOW_DECORATIONS), + MENU_LABEL(VIDEO_WINDOW_SAVE_POSITION), MENU_ENUM_LABEL_VALUE_QT_INFO, MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index 7b52bbb9c9..f8400e5d89 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -274,15 +275,18 @@ static void handshake_password(void *ignore, const char *line) { struct password_buf_s password_buf; char password[8+NETPLAY_PASS_LEN]; /* 8 for salt, 128 for password */ + char hash[NETPLAY_PASS_HASH_LEN+1]; /* + NULL terminator */ netplay_t *netplay = handshake_password_netplay; struct netplay_connection *connection = &netplay->connections[0]; snprintf(password, sizeof(password), "%08X", connection->salt); - strlcpy(password + 8, line, sizeof(password)-8); + if (!string_is_empty(line)) + strlcpy(password + 8, line, sizeof(password)-8); password_buf.cmd[0] = htonl(NETPLAY_CMD_PASSWORD); password_buf.cmd[1] = htonl(sizeof(password_buf.password)); - sha256_hash(password_buf.password, (uint8_t *) password, strlen(password)); + sha256_hash(hash, (uint8_t *) password, strlen(password)); + memcpy(password_buf.password, hash, NETPLAY_PASS_HASH_LEN); /* We have no way to handle an error here, so we'll let the next function error out */ if (netplay_send(&connection->send_packet_buffer, connection->fd, &password_buf, sizeof(password_buf))) @@ -750,8 +754,9 @@ bool netplay_handshake_pre_nick(netplay_t *netplay, bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) { - struct password_buf_s password_buf, corr_password_buf; + struct password_buf_s password_buf; char password[8+NETPLAY_PASS_LEN]; /* 8 for salt */ + char hash[NETPLAY_PASS_HASH_LEN+1]; /* + NULL terminator */ ssize_t recvd; char msg[512]; bool correct = false; @@ -787,11 +792,9 @@ bool netplay_handshake_pre_password(netplay_t *netplay, strlcpy(password + 8, settings->paths.netplay_password, sizeof(password)-8); - sha256_hash(corr_password_buf.password, - (uint8_t *) password, strlen(password)); + sha256_hash(hash, (uint8_t *) password, strlen(password)); - if (!memcmp(password_buf.password, - corr_password_buf.password, sizeof(password_buf.password))) + if (!memcmp(password_buf.password, hash, NETPLAY_PASS_HASH_LEN)) { correct = true; connection->can_play = true; @@ -802,11 +805,9 @@ bool netplay_handshake_pre_password(netplay_t *netplay, strlcpy(password + 8, settings->paths.netplay_spectate_password, sizeof(password)-8); - sha256_hash(corr_password_buf.password, - (uint8_t *) password, strlen(password)); + sha256_hash(hash, (uint8_t *) password, strlen(password)); - if (!memcmp(password_buf.password, - corr_password_buf.password, sizeof(password_buf.password))) + if (!memcmp(password_buf.password, hash, NETPLAY_PASS_HASH_LEN)) correct = true; } diff --git a/pkg/android/phoenix/jni/Android.mk b/pkg/android/phoenix/jni/Android.mk index c2f1802597..2523d3b80a 100644 --- a/pkg/android/phoenix/jni/Android.mk +++ b/pkg/android/phoenix/jni/Android.mk @@ -72,7 +72,7 @@ else DEFINES += -DHAVE_OPENGLES2 endif -DEFINES += -DRARCH_MOBILE -DHAVE_GRIFFIN -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_OPENGLES -DGLSL_DEBUG -DHAVE_DYLIB -DHAVE_EGL -DHAVE_GLSL -DHAVE_MENU -DHAVE_RGUI -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DINLINE=inline -DHAVE_THREADS -D__LIBRETRO__ -DHAVE_RSOUND -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DHAVE_NETPLAYDISCOVERY -DRARCH_INTERNAL -DHAVE_FILTERS_BUILTIN -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_SHADERPIPELINE -DHAVE_LIBRETRODB -DHAVE_STB_FONT -DHAVE_IMAGEVIEWER -DHAVE_UPDATE_ASSETS -DHAVE_CC_RESAMPLER -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -DHAVE_KEYMAPPER -DHAVE_NETWORKGAMEPAD -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_CHD -DHAVE_RUNAHEAD -DENABLE_HLSL +DEFINES += -DRARCH_MOBILE -DHAVE_GRIFFIN -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_OPENGLES -DGLSL_DEBUG -DHAVE_DYLIB -DHAVE_EGL -DHAVE_GLSL -DHAVE_MENU -DHAVE_RGUI -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DINLINE=inline -DHAVE_THREADS -D__LIBRETRO__ -DHAVE_RSOUND -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DHAVE_NETPLAYDISCOVERY -DRARCH_INTERNAL -DHAVE_FILTERS_BUILTIN -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_SHADERPIPELINE -DHAVE_LIBRETRODB -DHAVE_STB_FONT -DHAVE_IMAGEVIEWER -DHAVE_UPDATE_ASSETS -DHAVE_CC_RESAMPLER -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -DHAVE_KEYMAPPER -DHAVE_NETWORKGAMEPAD -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_CHD -DHAVE_RUNAHEAD -DENABLE_HLSL DEFINES += -DWANT_IFADDRS ifeq ($(HAVE_VULKAN),1) diff --git a/pkg/android/phoenix64/jni/Android.mk b/pkg/android/phoenix64/jni/Android.mk index 9862b63375..95cbe81754 100644 --- a/pkg/android/phoenix64/jni/Android.mk +++ b/pkg/android/phoenix64/jni/Android.mk @@ -72,7 +72,7 @@ else DEFINES += -DHAVE_OPENGLES2 endif -DEFINES += -DRARCH_MOBILE -DHAVE_GRIFFIN -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_OPENGLES -DGLSL_DEBUG -DHAVE_DYLIB -DHAVE_EGL -DHAVE_GLSL -DHAVE_MENU -DHAVE_RGUI -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DINLINE=inline -DHAVE_THREADS -D__LIBRETRO__ -DHAVE_RSOUND -DHAVE_NETWORKGAMEPAD -DHAVE_NETPLAYDISCOVERY -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_FILTERS_BUILTIN -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_SHADERPIPELINE -DHAVE_LIBRETRODB -DHAVE_STB_FONT -DHAVE_IMAGEVIEWER -DHAVE_UPDATE_ASSETS -DHAVE_CC_RESAMPLER -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -DHAVE_KEYMAPPER -DHAVE_NETWORKGAMEPAD -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_CHD -DHAVE_RUNAHEAD -DENABLE_HLSL +DEFINES += -DRARCH_MOBILE -DHAVE_GRIFFIN -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_OPENGLES -DGLSL_DEBUG -DHAVE_DYLIB -DHAVE_EGL -DHAVE_GLSL -DHAVE_MENU -DHAVE_RGUI -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DINLINE=inline -DHAVE_THREADS -D__LIBRETRO__ -DHAVE_RSOUND -DHAVE_NETWORKGAMEPAD -DHAVE_NETPLAYDISCOVERY -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_FILTERS_BUILTIN -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_SHADERPIPELINE -DHAVE_LIBRETRODB -DHAVE_STB_FONT -DHAVE_IMAGEVIEWER -DHAVE_UPDATE_ASSETS -DHAVE_CC_RESAMPLER -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -DHAVE_KEYMAPPER -DHAVE_NETWORKGAMEPAD -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_CHD -DHAVE_RUNAHEAD -DENABLE_HLSL DEFINES += -DWANT_IFADDRS ifeq ($(HAVE_VULKAN),1) diff --git a/pkg/apple/RetroArch.xcodeproj/project.pbxproj b/pkg/apple/RetroArch.xcodeproj/project.pbxproj index 66253f4f41..4ecdb6839c 100644 --- a/pkg/apple/RetroArch.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch.xcodeproj/project.pbxproj @@ -547,6 +547,7 @@ "-DHAVE_MATERIALUI", "-DHAVE_HID", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-DHAVE_MMAP", "-DHAVE_LIBRETRODB", @@ -611,6 +612,7 @@ "-DHAVE_MATERIALUI", "-DHAVE_HID", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-DHAVE_MMAP", "-DHAVE_LIBRETRODB", diff --git a/pkg/apple/RetroArch_PPC.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_PPC.xcodeproj/project.pbxproj index 15f9cadc81..d9353f870a 100644 --- a/pkg/apple/RetroArch_PPC.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_PPC.xcodeproj/project.pbxproj @@ -327,6 +327,7 @@ "-DHAVE_MATERIALUI", "-DHAVE_HID", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-DHAVE_MMAP", "-DHAVE_LIBRETRODB", @@ -404,6 +405,7 @@ "-DHAVE_MATERIALUI", "-DHAVE_HID", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-DHAVE_MMAP", "-DHAVE_LIBRETRODB", diff --git a/pkg/apple/RetroArch_iOS10.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS10.xcodeproj/project.pbxproj index e1461cca61..81a8b754a7 100644 --- a/pkg/apple/RetroArch_iOS10.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS10.xcodeproj/project.pbxproj @@ -372,6 +372,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -461,6 +462,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -516,6 +518,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/apple/RetroArch_iOS10_static.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS10_static.xcodeproj/project.pbxproj index 71564abe2b..fecacf79eb 100644 --- a/pkg/apple/RetroArch_iOS10_static.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS10_static.xcodeproj/project.pbxproj @@ -379,6 +379,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -467,6 +468,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -521,6 +523,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/apple/RetroArch_iOS11.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS11.xcodeproj/project.pbxproj index 510c0bd261..c8a7fa4b1a 100644 --- a/pkg/apple/RetroArch_iOS11.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS11.xcodeproj/project.pbxproj @@ -372,6 +372,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -462,6 +463,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -518,6 +520,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/apple/RetroArch_iOS11_static.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS11_static.xcodeproj/project.pbxproj index ebb461a418..9338ee20d0 100644 --- a/pkg/apple/RetroArch_iOS11_static.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS11_static.xcodeproj/project.pbxproj @@ -378,6 +378,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -466,6 +467,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -520,6 +522,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/apple/RetroArch_iOS6.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS6.xcodeproj/project.pbxproj index 59ff093d67..27410e395c 100644 --- a/pkg/apple/RetroArch_iOS6.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS6.xcodeproj/project.pbxproj @@ -385,6 +385,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", ); @@ -470,6 +471,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", ); @@ -521,6 +523,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", ); diff --git a/pkg/apple/RetroArch_iOS8.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS8.xcodeproj/project.pbxproj index bf69260f49..cbdfa26a96 100644 --- a/pkg/apple/RetroArch_iOS8.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS8.xcodeproj/project.pbxproj @@ -536,6 +536,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -625,6 +626,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -679,6 +681,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/apple/RetroArch_iOS9.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS9.xcodeproj/project.pbxproj index 1decfd22f3..cbb6e4f7f9 100644 --- a/pkg/apple/RetroArch_iOS9.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS9.xcodeproj/project.pbxproj @@ -401,6 +401,7 @@ "-DHAVE_FILTERS_BUILTIN", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -488,6 +489,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", @@ -541,6 +543,7 @@ "-DHAVE_7ZIP", "-DHAVE_MATERIALUI", "-DHAVE_XMB", + "-DHAVE_OZONE", "-DHAVE_SHADERPIPELINE", "-D_LZMA_UINT32_IS_ULONG", "-DHAVE_MFI", diff --git a/pkg/msvc/msvc-2017/RetroArch-msvc2017.vcxproj b/pkg/msvc/msvc-2017/RetroArch-msvc2017.vcxproj index 162d564902..f228bad8bf 100644 --- a/pkg/msvc/msvc-2017/RetroArch-msvc2017.vcxproj +++ b/pkg/msvc/msvc-2017/RetroArch-msvc2017.vcxproj @@ -371,7 +371,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -391,7 +391,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -412,7 +412,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -433,7 +433,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -454,7 +454,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -474,7 +474,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -495,7 +495,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -516,7 +516,7 @@ Level3 Disabled - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_FBO;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreadedDebug CompileAsCpp @@ -539,7 +539,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -564,7 +564,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -590,7 +590,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -616,7 +616,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_MENU;HAVE_RGUI;HAVE_GL_SYNC;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -642,7 +642,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -667,7 +667,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -693,7 +693,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp @@ -719,7 +719,7 @@ MaxSpeed true true - WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT + WIN32;RARCH_INTERNAL;HAVE_CC_RESAMPLER;WANT_GLSLANG;HAVE_SLANG;HAVE_GLSLANG;HAVE_SPIRV_CROSS;HAVE_UPDATE_ASSETS;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_D3D12;HAVE_VULKAN;ENABLE_HLSL;RC_DISABLE_LUA;HAVE_WASAPI;HAVE_CG;HAVE_GLSL;HAVE_CHEEVOS;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_FBO;HAVE_ZLIB;HAVE_QT;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_DINPUT;HAVE_XINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_NETPLAYDISCOVERY;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;WANT_ZLIB;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\..\;$(MSBuildProjectDirectory)\..\..\..\deps\rcheevos\include;$(CG_INC_PATH);$(MSBuildProjectDirectory)\..\..\..\deps\zlib;$(MSBuildProjectDirectory)\..\..\..\libretro-common\include;$(MSBuildProjectDirectory)\..\..\..\deps;$(MSBuildProjectDirectory)\..\..\..\deps\glslang;$(MSBuildProjectDirectory)\..\..\..\deps\SPIRV-Cross;$(MSBuildProjectDirectory)\..\..\..\deps\stb;$(MSBuildProjectDirectory)\..\..\..\gfx\include;%(AdditionalIncludeDirectories) MultiThreaded CompileAsCpp diff --git a/record/record_driver.c b/record/record_driver.c index 9b2f4afe37..9426b58e2f 100644 --- a/record/record_driver.c +++ b/record/record_driver.c @@ -539,7 +539,7 @@ void recording_driver_update_streaming_url(void) else { /* To-Do: Show input box for twitch_stream_key*/ - RARCH_LOG("[recording] twitch streaming key empty"); + RARCH_LOG("[recording] twitch streaming key empty\n"); } break; } @@ -553,7 +553,7 @@ void recording_driver_update_streaming_url(void) else { /* To-Do: Show input box for youtube_stream_key*/ - RARCH_LOG("[recording] youtube streaming key empty"); + RARCH_LOG("[recording] youtube streaming key empty\n"); } break; }