mirror of
https://github.com/libretro/RetroArch.git
synced 2024-06-02 19:57:24 -04:00
(3DS) Add bottom screen menu (#12470)
* (3DS) Add bottom screen menu -> User can save/load state on botom screen with thumbnail. -> Call a save_state_to_file() when RAM state has data to write a disk. -> If the bottom screen needs updating, swap the bottom framebuffers. Add: SAVE/LODE STATE TO RAM -> This is useful for devices with slow I/O -> 3DS bottom save state use CMD_EVENT_SAVE_STATE_TO_RAM -> 3DS bottom load state use CMD_EVENT_LOAD_STATE when RAM state has no data -> 3DS bottom load state use CMD_EVENT_LOAD_STATE_FROM_RAM when RAM sate has data * Rewrite path_get_state to retroarch_get_current_savestate_path * Fix unterminated state_path
This commit is contained in:
parent
51dcad6cb3
commit
8adc24ecbc
|
@ -2,6 +2,7 @@ TARGET := retroarch_3ds
|
|||
LIBRETRO =
|
||||
|
||||
DEBUG = 0
|
||||
CONSOLE_LOG = 0
|
||||
GRIFFIN_BUILD = 1
|
||||
WHOLE_ARCHIVE_LINK = 0
|
||||
BUILD_3DSX = 1
|
||||
|
@ -154,6 +155,10 @@ else
|
|||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
ifeq ($(CONSOLE_LOG), 1)
|
||||
CFLAGS += -DCONSOLE_LOG
|
||||
endif
|
||||
|
||||
ifeq ($(LIBCTRU_NO_DEPRECATION), 1)
|
||||
CFLAGS += -DLIBCTRU_NO_DEPRECATION
|
||||
endif
|
||||
|
|
|
@ -2,6 +2,7 @@ TARGET := retroarch_3ds_salamander
|
|||
LIBRETRO =
|
||||
|
||||
DEBUG = 0
|
||||
CONSOLE_LOG = 0
|
||||
BUILD_3DSX = 1
|
||||
BUILD_3DS = 0
|
||||
BUILD_CIA = 1
|
||||
|
@ -95,6 +96,10 @@ else
|
|||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
ifeq ($(CONSOLE_LOG), 1)
|
||||
CFLAGS += -DCONSOLE_LOG
|
||||
endif
|
||||
|
||||
CFLAGS += -I. -Ideps/7zip -Ideps/stb -Ilibretro-common/include -Ilibretro-common/include/compat/zlib
|
||||
|
||||
#CFLAGS += -DRARCH_INTERNAL
|
||||
|
|
|
@ -79,13 +79,16 @@ enum event_command
|
|||
CMD_EVENT_UNLOAD_CORE,
|
||||
CMD_EVENT_CLOSE_CONTENT,
|
||||
CMD_EVENT_LOAD_STATE,
|
||||
CMD_EVENT_LOAD_STATE_FROM_RAM,
|
||||
/* Swaps the current state with what's on the undo load buffer */
|
||||
CMD_EVENT_UNDO_LOAD_STATE,
|
||||
/* Rewrites a savestate on disk */
|
||||
CMD_EVENT_UNDO_SAVE_STATE,
|
||||
CMD_EVENT_SAVE_STATE,
|
||||
CMD_EVENT_SAVE_STATE_TO_RAM,
|
||||
CMD_EVENT_SAVE_STATE_DECREMENT,
|
||||
CMD_EVENT_SAVE_STATE_INCREMENT,
|
||||
CMD_EVENT_RAM_STATE_TO_FILE,
|
||||
/* Takes screenshot. */
|
||||
CMD_EVENT_TAKE_SCREENSHOT,
|
||||
/* Quits RetroArch. */
|
||||
|
|
|
@ -45,6 +45,15 @@ bool content_load_ram_file(unsigned slot);
|
|||
/* Save a RAM state from memory to disk. */
|
||||
bool content_save_ram_file(unsigned slot, bool compress);
|
||||
|
||||
/* Load a state from memory. */
|
||||
bool content_load_state_from_ram(void);
|
||||
|
||||
/* Save a state to memory. */
|
||||
bool content_save_state_to_ram(void);
|
||||
|
||||
/* Save a ram state from memory to disk. */
|
||||
bool content_ram_state_to_file(const char *path);
|
||||
|
||||
/* Load a state from disk to memory. */
|
||||
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
|
||||
|
||||
|
|
|
@ -162,8 +162,10 @@ static void frontend_ctr_deinit(void* data)
|
|||
verbosity_enable();
|
||||
retro_main_log_file_init(NULL, false);
|
||||
|
||||
#ifdef CONSOLE_LOG
|
||||
if (ctr_bottom_screen_enabled && (ctr_fork_mode == FRONTEND_FORK_NONE))
|
||||
wait_for_input();
|
||||
#endif
|
||||
|
||||
CFGU_GetModelNintendo2DS(¬_2DS);
|
||||
|
||||
|
@ -419,13 +421,15 @@ void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id)
|
|||
id,
|
||||
(u32*)gfxBottomFramebuffers[id],
|
||||
(u32*)gfxBottomFramebuffers[id],
|
||||
240 * 2,
|
||||
GSP_RGB565_OES);
|
||||
240 * 3,
|
||||
GSP_BGR8_OES);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONSOLE_LOG
|
||||
PrintConsole* ctrConsole;
|
||||
#endif
|
||||
|
||||
static void frontend_ctr_init(void* data)
|
||||
{
|
||||
|
@ -436,10 +440,10 @@ static void frontend_ctr_init(void* data)
|
|||
|
||||
verbosity_enable();
|
||||
|
||||
gfxInit(GSP_BGR8_OES, GSP_RGB565_OES, false);
|
||||
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
|
||||
|
||||
u32 topSize = 400 * 240 * 3;
|
||||
u32 bottomSize = 320 * 240 * 2;
|
||||
u32 bottomSize = 320 * 240 * 3;
|
||||
|
||||
#ifdef USE_CTRULIB_2
|
||||
linearFree(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL));
|
||||
|
@ -473,7 +477,9 @@ static void frontend_ctr_init(void* data)
|
|||
gfxSetFramebufferInfo(GFX_BOTTOM, 0);
|
||||
|
||||
gfxSet3D(true);
|
||||
#ifdef CONSOLE_LOG
|
||||
ctrConsole = consoleInit(GFX_BOTTOM, NULL);
|
||||
#endif
|
||||
|
||||
/* enable access to all service calls when possible. */
|
||||
if (svchax_init)
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
|
||||
#define COLOR_ABGR(r, g, b, a) (((unsigned)(a) << 24) | ((b) << 16) | ((g) << 8) | ((r) << 0))
|
||||
|
||||
#define CTR_TOP_FRAMEBUFFER_WIDTH 400
|
||||
#define CTR_TOP_FRAMEBUFFER_HEIGHT 240
|
||||
#define CTR_TOP_FRAMEBUFFER_WIDTH 400
|
||||
#define CTR_TOP_FRAMEBUFFER_HEIGHT 240
|
||||
#define CTR_BOTTOM_FRAMEBUFFER_WIDTH 320
|
||||
#define CTR_BOTTOM_FRAMEBUFFER_HEIGHT 240
|
||||
#define CTR_STATE_DATE_SIZE 11
|
||||
|
||||
#ifdef USE_CTRULIB_2
|
||||
extern u8* gfxTopLeftFramebuffers[2];
|
||||
|
@ -30,7 +33,9 @@ extern u8* gfxTopRightFramebuffers[2];
|
|||
extern u8* gfxBottomFramebuffers[2];
|
||||
#endif
|
||||
|
||||
#ifdef CONSOLE_LOG
|
||||
extern PrintConsole* ctrConsole;
|
||||
#endif
|
||||
|
||||
extern const u8 ctr_sprite_shbin[];
|
||||
extern const u32 ctr_sprite_shbin_size;
|
||||
|
@ -58,6 +63,13 @@ typedef enum
|
|||
CTR_VIDEO_MODE_LAST
|
||||
} ctr_video_mode_enum;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CTR_BOTTOM_MENU_NOT_AVAILABLE = 0,
|
||||
CTR_BOTTOM_MENU_DEFAULT,
|
||||
CTR_BOTTOM_MENU_SELECT,
|
||||
} ctr_bottom_menu;
|
||||
|
||||
typedef struct ctr_video
|
||||
{
|
||||
struct
|
||||
|
@ -67,6 +79,7 @@ typedef struct ctr_video
|
|||
void* left;
|
||||
void* right;
|
||||
}top;
|
||||
void* bottom;
|
||||
}drawbuffers;
|
||||
void* depthbuffer;
|
||||
|
||||
|
@ -116,11 +129,10 @@ typedef struct ctr_video
|
|||
bool overlay_full_screen;
|
||||
#endif
|
||||
|
||||
void* empty_framebuffer;
|
||||
|
||||
aptHookCookie lcd_aptHook;
|
||||
ctr_video_mode_enum video_mode;
|
||||
int current_buffer_top;
|
||||
int current_buffer_bottom;
|
||||
|
||||
bool p3d_event_pending;
|
||||
bool ppf_event_pending;
|
||||
|
@ -133,6 +145,17 @@ typedef struct ctr_video
|
|||
int size;
|
||||
}vertex_cache;
|
||||
|
||||
bool init_bottom_menu;
|
||||
bool refresh_bottom_menu;
|
||||
bool render_font_bottom;
|
||||
bool render_state_from_png_file;
|
||||
bool state_data_on_ram;
|
||||
bool state_data_exist;
|
||||
char state_date[CTR_STATE_DATE_SIZE];
|
||||
int state_slot;
|
||||
ctr_bottom_menu bottom_menu;
|
||||
ctr_bottom_menu prev_bottom_menu;
|
||||
struct ctr_bottom_texture_data *bottom_textures;
|
||||
} ctr_video_t;
|
||||
|
||||
typedef struct ctr_texture
|
||||
|
@ -156,6 +179,13 @@ struct ctr_overlay_data
|
|||
};
|
||||
#endif
|
||||
|
||||
struct ctr_bottom_texture_data
|
||||
{
|
||||
uintptr_t texture;
|
||||
ctr_vertex_t* frame_coords;
|
||||
ctr_scale_vector_t scale_vector;
|
||||
};
|
||||
|
||||
static INLINE void ctr_set_scale_vector(ctr_scale_vector_t* vec,
|
||||
int viewport_width, int viewport_height,
|
||||
int texture_width, int texture_height)
|
||||
|
|
|
@ -50,6 +50,16 @@
|
|||
#include "../../tasks/tasks_internal.h"
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
CTR_TEXTURE_BOTTOM_MENU,
|
||||
CTR_TEXTURE_STATE_THUMBNAIL,
|
||||
CTR_TEXTURE_LAST
|
||||
};
|
||||
|
||||
/* TODO/FIXME - global referenced outside */
|
||||
extern uint64_t lifecycle_state;
|
||||
|
||||
/* An annoyance...
|
||||
* Have to keep track of bottom screen enable state
|
||||
* externally, otherwise cannot detect current state
|
||||
|
@ -244,6 +254,551 @@ static void ctr_update_viewport(
|
|||
|
||||
}
|
||||
|
||||
static const char *ctr_texture_path(unsigned id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case CTR_TEXTURE_BOTTOM_MENU:
|
||||
return "ctr/bottom_menu.png";
|
||||
case CTR_TEXTURE_STATE_THUMBNAIL:
|
||||
{
|
||||
static char texture_path[PATH_MAX_LENGTH];
|
||||
|
||||
char state_path[PATH_MAX_LENGTH];
|
||||
if (!retroarch_get_current_savestate_path(state_path,
|
||||
sizeof(state_path)))
|
||||
return NULL;
|
||||
|
||||
snprintf(texture_path, sizeof(texture_path),
|
||||
"%s.png", state_path);
|
||||
|
||||
return path_basename(texture_path);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ctr_update_state_date(void *data)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
struct tm *t = localtime(&now);
|
||||
sprintf(ctr->state_date, "%02d/%02d/%d",
|
||||
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
|
||||
}
|
||||
|
||||
static bool ctr_update_state_date_from_file(void *data)
|
||||
{
|
||||
char state_path[PATH_MAX_LENGTH];
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
if (!retroarch_get_current_savestate_path(state_path, sizeof(state_path)))
|
||||
return false;
|
||||
|
||||
#ifdef USE_CTRULIB_2
|
||||
time_t mtime;
|
||||
bool file_exists = archive_getmtime(state_path + 5, &mtime) == 0;
|
||||
#else
|
||||
u64 mtime;
|
||||
bool file_exists = sdmc_getmtime(state_path + 5, &mtime) == 0;
|
||||
#endif
|
||||
if (!file_exists)
|
||||
{
|
||||
ctr->state_data_exist = false;
|
||||
snprintf(ctr->state_date, sizeof(ctr->state_date), "00/00/0000");
|
||||
return false;
|
||||
}
|
||||
|
||||
ctr->state_data_exist = true;
|
||||
|
||||
#ifdef USE_CTRULIB_2
|
||||
struct tm *t = localtime(&mtime);
|
||||
#else
|
||||
time_t ft = mtime;
|
||||
struct tm *t = localtime(&ft);
|
||||
#endif
|
||||
sprintf(ctr->state_date, "%02d/%02d/%d",
|
||||
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ctr_state_thumbnail_geom(void *data)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t *) data;
|
||||
struct ctr_bottom_texture_data *o = NULL;
|
||||
const int target_width = 120;
|
||||
const int target_height = 90;
|
||||
unsigned width, height;
|
||||
|
||||
if (ctr)
|
||||
o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
||||
|
||||
if (!o)
|
||||
return;
|
||||
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
float scale = (float) target_width / texture->active_width;
|
||||
if (target_width > texture->active_width * scale) {
|
||||
scale = (float) (target_width + 1) / texture->active_width;
|
||||
}
|
||||
|
||||
o->frame_coords->u0 = 0;
|
||||
o->frame_coords->v0 = 0;
|
||||
o->frame_coords->u1 = texture->active_width;
|
||||
o->frame_coords->v1 = texture->active_height;
|
||||
|
||||
int x_offset = 184;
|
||||
int y_offset = 46 + (target_height - texture->active_height * scale) / 2;
|
||||
|
||||
o->frame_coords->x0 = x_offset;
|
||||
o->frame_coords->y0 = y_offset;
|
||||
o->frame_coords->x1 = o->frame_coords->x0 + texture->active_width * scale;
|
||||
o->frame_coords->y1 = o->frame_coords->y0 + texture->active_height * scale;
|
||||
|
||||
ctr_set_scale_vector(&o->scale_vector,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
|
||||
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
texture->width,
|
||||
texture->height);
|
||||
}
|
||||
|
||||
static bool ctr_load_bottom_texture(void *data)
|
||||
{
|
||||
unsigned i;
|
||||
const char *dir_assets;
|
||||
|
||||
ctr_video_t *ctr = (ctr_video_t *)data;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
for (i = 0; i < CTR_TEXTURE_LAST; i++)
|
||||
{
|
||||
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
|
||||
dir_assets = dir_get_ptr(RARCH_DIR_SAVESTATE);
|
||||
else
|
||||
dir_assets = settings->paths.directory_assets;
|
||||
|
||||
if (gfx_display_reset_textures_list(
|
||||
ctr_texture_path(i), dir_assets,
|
||||
&ctr->bottom_textures[i].texture,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
||||
{
|
||||
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
|
||||
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
||||
|
||||
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
|
||||
{
|
||||
ctr_state_thumbnail_geom(ctr);
|
||||
ctr->render_state_from_png_file = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
|
||||
o->frame_coords->u0 = 0;
|
||||
o->frame_coords->v0 = 0;
|
||||
o->frame_coords->u1 = texture->width;
|
||||
o->frame_coords->v1 = texture->height;
|
||||
|
||||
o->frame_coords->x0 = 0;
|
||||
o->frame_coords->y0 = 0;
|
||||
o->frame_coords->x1 = o->frame_coords->x0 + texture->width;
|
||||
o->frame_coords->y1 = o->frame_coords->y0 + texture->height;
|
||||
|
||||
ctr_set_scale_vector(&o->scale_vector,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
|
||||
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
texture->width,
|
||||
texture->height);
|
||||
}
|
||||
}
|
||||
else if (i == CTR_TEXTURE_BOTTOM_MENU)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void save_state_to_file(void *data)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
char state_path[PATH_MAX_LENGTH];
|
||||
global_t *global = global_get_ptr();
|
||||
const char *name_savestate = global->name.savestate;
|
||||
|
||||
if (ctr->state_slot > 0)
|
||||
snprintf(state_path, sizeof(state_path), "%s%d", name_savestate,
|
||||
ctr->state_slot);
|
||||
else if (ctr->state_slot < 0)
|
||||
fill_pathname_join_delim(state_path,
|
||||
name_savestate, "auto", '.', sizeof(state_path));
|
||||
else
|
||||
strlcpy(state_path, name_savestate, sizeof(state_path));
|
||||
|
||||
command_event(CMD_EVENT_RAM_STATE_TO_FILE, state_path);
|
||||
}
|
||||
|
||||
static void bottom_menu_control(void* data, bool lcd_bottom)
|
||||
{
|
||||
touchPosition state_tmp_touch;
|
||||
uint32_t state_tmp = 0;
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
settings_t *settings = config_get_ptr();
|
||||
int config_slot = settings->ints.state_slot;
|
||||
|
||||
if (!ctr->init_bottom_menu)
|
||||
{
|
||||
if (ctr_load_bottom_texture(ctr))
|
||||
{
|
||||
ctr_update_state_date_from_file(ctr);
|
||||
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
|
||||
}
|
||||
|
||||
ctr->init_bottom_menu = true;
|
||||
}
|
||||
|
||||
BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
|
||||
state_tmp = hidKeysDown();
|
||||
hidTouchRead(&state_tmp_touch);
|
||||
|
||||
if (state_tmp & KEY_TOUCH)
|
||||
{
|
||||
#ifdef CONSOLE_LOG
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
return;
|
||||
#endif
|
||||
if (!rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
||||
return;
|
||||
|
||||
if (!lcd_bottom ||
|
||||
ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE)
|
||||
{
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctr->bottom_menu)
|
||||
{
|
||||
case CTR_BOTTOM_MENU_DEFAULT:
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
break;
|
||||
case CTR_BOTTOM_MENU_SELECT:
|
||||
if (state_tmp_touch.px > 8 &&
|
||||
state_tmp_touch.px < 164 &&
|
||||
state_tmp_touch.py > 9 &&
|
||||
state_tmp_touch.py < 86)
|
||||
{
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
}
|
||||
else if (state_tmp_touch.px > 8 &&
|
||||
state_tmp_touch.px < 164 &&
|
||||
state_tmp_touch.py > 99 &&
|
||||
state_tmp_touch.py < 230)
|
||||
{
|
||||
char screenshot_full_path[PATH_MAX_LENGTH];
|
||||
|
||||
struct ctr_bottom_texture_data *o =
|
||||
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
||||
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
if (texture)
|
||||
linearFree(texture->data);
|
||||
else
|
||||
{
|
||||
o->texture = (uintptr_t) calloc(1, sizeof(ctr_texture_t));
|
||||
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
||||
texture = (ctr_texture_t *) o->texture;
|
||||
}
|
||||
|
||||
texture->width = ctr->texture_width;
|
||||
texture->height = ctr->texture_width;
|
||||
texture->active_width = ctr->frame_coords->u1;
|
||||
texture->active_height = ctr->frame_coords->v1;
|
||||
|
||||
texture->data = linearAlloc(
|
||||
ctr->texture_width * ctr->texture_height *
|
||||
(ctr->rgb32? 4:2));
|
||||
|
||||
memcpy(texture->data, ctr->texture_swizzled,
|
||||
ctr->texture_width * ctr->texture_height *
|
||||
(ctr->rgb32? 4:2));
|
||||
|
||||
ctr_state_thumbnail_geom(ctr);
|
||||
|
||||
ctr->state_data_exist = true;
|
||||
ctr->state_data_on_ram = true;
|
||||
ctr->render_state_from_png_file = false;
|
||||
|
||||
ctr_update_state_date(ctr);
|
||||
|
||||
command_event(CMD_EVENT_SAVE_STATE_TO_RAM, NULL);
|
||||
|
||||
if (settings->bools.savestate_thumbnail_enable)
|
||||
{
|
||||
sprintf(screenshot_full_path, "%s/%s",
|
||||
dir_get_ptr(RARCH_DIR_SAVESTATE),
|
||||
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL));
|
||||
|
||||
take_screenshot(NULL, screenshot_full_path, true,
|
||||
video_driver_cached_frame_has_valid_framebuffer(),
|
||||
true, true);
|
||||
}
|
||||
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
}
|
||||
else if (state_tmp_touch.px > 176 &&
|
||||
state_tmp_touch.px < 311 &&
|
||||
state_tmp_touch.py > 9 &&
|
||||
state_tmp_touch.py < 230 &&
|
||||
ctr->state_data_exist)
|
||||
{
|
||||
if (ctr->state_data_on_ram)
|
||||
command_event(CMD_EVENT_LOAD_STATE_FROM_RAM, NULL);
|
||||
else
|
||||
command_event(CMD_EVENT_LOAD_STATE, NULL);
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ctr->refresh_bottom_menu = true;
|
||||
}
|
||||
|
||||
if (ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE ||
|
||||
!rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
||||
return;
|
||||
|
||||
if (ctr->state_slot != config_slot)
|
||||
{
|
||||
if (ctr->state_data_on_ram)
|
||||
{
|
||||
save_state_to_file(ctr);
|
||||
ctr->state_data_on_ram = false;
|
||||
}
|
||||
|
||||
ctr->state_slot = config_slot;
|
||||
|
||||
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
|
||||
if (texture)
|
||||
{
|
||||
linearFree(texture->data);
|
||||
linearFree(o->frame_coords);
|
||||
o->texture = 0;
|
||||
}
|
||||
|
||||
if (ctr_update_state_date_from_file(ctr))
|
||||
{
|
||||
if(gfx_display_reset_textures_list(
|
||||
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL),
|
||||
dir_get_ptr(RARCH_DIR_SAVESTATE),
|
||||
&o->texture,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
||||
{
|
||||
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
||||
ctr_state_thumbnail_geom(ctr);
|
||||
ctr->render_state_from_png_file = true;
|
||||
}
|
||||
}
|
||||
|
||||
ctr->refresh_bottom_menu = true;
|
||||
}
|
||||
|
||||
if (menu_driver_is_alive())
|
||||
ctr->bottom_menu = CTR_BOTTOM_MENU_SELECT;
|
||||
else
|
||||
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
|
||||
|
||||
if (ctr->prev_bottom_menu != ctr->bottom_menu)
|
||||
{
|
||||
ctr->prev_bottom_menu = ctr->bottom_menu;
|
||||
ctr->refresh_bottom_menu = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void font_driver_render_msg_bottom(
|
||||
void *data,
|
||||
const char *msg,
|
||||
const void *_params,
|
||||
void *font_data)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
ctr->render_font_bottom = true;
|
||||
font_driver_render_msg(ctr, msg, _params, font_data);
|
||||
ctr->render_font_bottom = false;
|
||||
}
|
||||
|
||||
static void ctr_render_bottom_screen(void *data)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return;
|
||||
|
||||
if (!ctr->refresh_bottom_menu)
|
||||
return;
|
||||
|
||||
struct font_params params = { 0, };
|
||||
params.text_align = TEXT_ALIGN_CENTER;
|
||||
params.color = COLOR_ABGR(255, 255, 255, 255);
|
||||
|
||||
switch (ctr->bottom_menu)
|
||||
{
|
||||
case CTR_BOTTOM_MENU_NOT_AVAILABLE:
|
||||
{
|
||||
params.scale = 1.6f;
|
||||
params.x = 0.0f;
|
||||
params.y = 0.5f;
|
||||
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND),
|
||||
¶ms, NULL);
|
||||
}
|
||||
break;
|
||||
case CTR_BOTTOM_MENU_DEFAULT:
|
||||
{
|
||||
params.scale = 1.6f;
|
||||
params.x = 0.0f;
|
||||
params.y = 0.5f;
|
||||
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_DEFAULT),
|
||||
¶ms, NULL);
|
||||
}
|
||||
break;
|
||||
case CTR_BOTTOM_MENU_SELECT:
|
||||
{
|
||||
params.scale = 1.48f;
|
||||
params.color = COLOR_ABGR(255, 255, 255, 255);
|
||||
|
||||
/* draw state thumbnail */
|
||||
if (ctr->state_data_exist) {
|
||||
struct ctr_bottom_texture_data *o = (struct ctr_bottom_texture_data*)
|
||||
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
||||
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
if (texture)
|
||||
{
|
||||
GPU_TEXCOLOR colorType = GPU_RGBA8;
|
||||
if (!ctr->render_state_from_png_file && !ctr->rgb32)
|
||||
colorType = GPU_RGB565;
|
||||
|
||||
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
|
||||
texture->width, texture->height,
|
||||
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
||||
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
||||
colorType);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
||||
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
|
||||
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
|
||||
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
|
||||
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x = 0.266f;
|
||||
params.y = 0.64f;
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL),
|
||||
¶ms, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x = 0.266f;
|
||||
params.y = 0.64f;
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_DATA),
|
||||
¶ms, NULL);
|
||||
}
|
||||
|
||||
/* draw bottom menu */
|
||||
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_BOTTOM_MENU];
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
|
||||
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
|
||||
texture->width, texture->height,
|
||||
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
||||
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
||||
GPU_RGBA8);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
||||
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
|
||||
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
|
||||
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
|
||||
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
||||
|
||||
/* draw resume game */
|
||||
params.x = -0.178f;
|
||||
params.y = 0.78f;
|
||||
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_RESUME),
|
||||
¶ms, NULL);
|
||||
|
||||
/* draw create restore point */
|
||||
params.x = -0.178f;
|
||||
params.y = 0.33f;
|
||||
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_SAVE_STATE),
|
||||
¶ms, NULL);
|
||||
|
||||
/* draw load restore point */
|
||||
params.x = 0.266f;
|
||||
params.y = 0.24f;
|
||||
|
||||
font_driver_render_msg_bottom(ctr,
|
||||
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_LOAD_STATE),
|
||||
¶ms, NULL);
|
||||
|
||||
/* draw date */
|
||||
params.x = 0.266f;
|
||||
params.y = 0.87f;
|
||||
font_driver_render_msg_bottom(ctr, ctr->state_date,
|
||||
¶ms, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ctr_set_bottom_screen_enable(bool enabled)
|
||||
{
|
||||
Handle lcd_handle;
|
||||
u8 not_2DS;
|
||||
|
||||
CFGU_GetModelNintendo2DS(¬_2DS);
|
||||
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = enabled? 0x00110040: 0x00120040;
|
||||
cmdbuf[1] = 2;
|
||||
svcSendSyncRequest(lcd_handle);
|
||||
svcCloseHandle(lcd_handle);
|
||||
}
|
||||
|
||||
ctr_bottom_screen_enabled = enabled;
|
||||
}
|
||||
|
||||
static void ctr_lcd_aptHook(APT_HookType hook, void* param)
|
||||
{
|
||||
ctr_video_t *ctr = (ctr_video_t*)param;
|
||||
|
@ -303,16 +858,12 @@ static void ctr_lcd_aptHook(APT_HookType hook, void* param)
|
|||
|
||||
if ((hook == APTHOOK_ONSUSPEND) || (hook == APTHOOK_ONRESTORE) || (hook == APTHOOK_ONWAKEUP))
|
||||
{
|
||||
Handle lcd_handle;
|
||||
u8 not_2DS;
|
||||
CFGU_GetModelNintendo2DS(¬_2DS);
|
||||
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
|
||||
ctr_set_bottom_screen_enable(hook == APTHOOK_ONSUSPEND);
|
||||
|
||||
if (ctr->state_data_on_ram)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = ((hook == APTHOOK_ONSUSPEND) || ctr_bottom_screen_enabled)? 0x00110040: 0x00120040;
|
||||
cmdbuf[1] = 2;
|
||||
svcSendSyncRequest(lcd_handle);
|
||||
svcCloseHandle(lcd_handle);
|
||||
save_state_to_file(ctr);
|
||||
ctr->state_data_on_ram = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,34 +893,11 @@ static bool ctr_tasks_finder(retro_task_t *task,void *userdata)
|
|||
task_finder_data_t ctr_tasks_finder_data = {ctr_tasks_finder, NULL};
|
||||
#endif
|
||||
|
||||
static void ctr_set_bottom_screen_enable(void* data, bool enabled)
|
||||
{
|
||||
Handle lcd_handle;
|
||||
u8 not_2DS;
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return;
|
||||
|
||||
gfxBottomFramebuffers[0] = enabled ? (u8*)ctrConsole->frameBuffer:
|
||||
(u8*)ctr->empty_framebuffer;
|
||||
|
||||
CFGU_GetModelNintendo2DS(¬_2DS);
|
||||
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = enabled? 0x00110040: 0x00120040;
|
||||
cmdbuf[1] = 2;
|
||||
svcSendSyncRequest(lcd_handle);
|
||||
svcCloseHandle(lcd_handle);
|
||||
}
|
||||
|
||||
ctr_bottom_screen_enabled = enabled;
|
||||
}
|
||||
|
||||
static void* ctr_init(const video_info_t* video,
|
||||
input_driver_t** input, void** input_data)
|
||||
{
|
||||
size_t i;
|
||||
float refresh_rate;
|
||||
u8 device_model = 0xFF;
|
||||
void* ctrinput = NULL;
|
||||
|
@ -392,6 +920,7 @@ static void* ctr_init(const video_info_t* video,
|
|||
|
||||
ctr->drawbuffers.top.left = vramAlloc(CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
|
||||
ctr->drawbuffers.top.right = (void*)((uint32_t*)ctr->drawbuffers.top.left + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT);
|
||||
ctr->drawbuffers.bottom = vramAlloc(CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
|
||||
|
||||
ctr->display_list_size = 0x4000;
|
||||
ctr->display_list = linearAlloc(ctr->display_list_size * sizeof(uint32_t));
|
||||
|
@ -401,6 +930,22 @@ static void* ctr_init(const video_info_t* video,
|
|||
ctr->vertex_cache.buffer = linearAlloc(ctr->vertex_cache.size * sizeof(ctr_vertex_t));
|
||||
ctr->vertex_cache.current = ctr->vertex_cache.buffer;
|
||||
|
||||
ctr->bottom_textures = (struct ctr_bottom_texture_data *)calloc(CTR_TEXTURE_LAST,
|
||||
sizeof(*ctr->bottom_textures));
|
||||
|
||||
ctr->init_bottom_menu = false;
|
||||
ctr->state_data_exist = false;
|
||||
ctr->state_data_on_ram = false;
|
||||
ctr->render_font_bottom = false;
|
||||
ctr->refresh_bottom_menu = true;
|
||||
ctr->render_state_from_png_file = false;
|
||||
ctr->bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
|
||||
ctr->prev_bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
|
||||
ctr->state_slot = settings->ints.state_slot;
|
||||
|
||||
snprintf(ctr->state_date, sizeof(ctr->state_date), "%s", "00/00/0000");
|
||||
ctr->state_date[CTR_STATE_DATE_SIZE - 1] = '\0';
|
||||
|
||||
ctr->rgb32 = video->rgb32;
|
||||
ctr->texture_width = video->input_scale * RARCH_SCALE_BASE;
|
||||
ctr->texture_height = video->input_scale * RARCH_SCALE_BASE;
|
||||
|
@ -512,6 +1057,7 @@ static void* ctr_init(const video_info_t* video,
|
|||
ctr->smooth = video->smooth;
|
||||
ctr->vsync = video->vsync;
|
||||
ctr->current_buffer_top = 0;
|
||||
ctr->current_buffer_bottom = 0;
|
||||
|
||||
/* Only O3DS and O3DSXL support running in 'dual-framebuffer'
|
||||
* mode with the parallax barrier disabled
|
||||
|
@ -520,9 +1066,6 @@ static void* ctr_init(const video_info_t* video,
|
|||
CFGU_GetSystemModel(&device_model); /* (0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL) */
|
||||
ctr->supports_parallax_disable = (device_model == 0) || (device_model == 1);
|
||||
|
||||
ctr->empty_framebuffer = linearAlloc(320 * 240 * 2);
|
||||
memset(ctr->empty_framebuffer, 0, 320 * 240 * 2);
|
||||
|
||||
refresh_rate = (32730.0 * 8192.0) / 4481134.0;
|
||||
|
||||
driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &refresh_rate);
|
||||
|
@ -539,7 +1082,7 @@ static void* ctr_init(const video_info_t* video,
|
|||
|
||||
/* Set bottom screen enable state, if required */
|
||||
if (lcd_bottom != ctr_bottom_screen_enabled)
|
||||
ctr_set_bottom_screen_enable(ctr, lcd_bottom);
|
||||
ctr_set_bottom_screen_enable(lcd_bottom);
|
||||
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank0,
|
||||
(ThreadFunc)ctr_vsync_hook, ctr, false);
|
||||
|
@ -557,12 +1100,10 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
unsigned pitch, const char* msg, video_frame_info_t *video_info)
|
||||
{
|
||||
static uint64_t currentTick,lastTick;
|
||||
touchPosition state_tmp_touch;
|
||||
extern GSPGPU_FramebufferInfo topFramebufferInfo;
|
||||
extern GSPGPU_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo;
|
||||
extern u8* gfxSharedMemory;
|
||||
extern u8 gfxThreadID;
|
||||
uint32_t diff;
|
||||
uint32_t state_tmp = 0;
|
||||
ctr_video_t *ctr = (ctr_video_t*)data;
|
||||
static float fps = 0.0;
|
||||
static int total_frames = 0;
|
||||
|
@ -584,6 +1125,7 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
#ifdef HAVE_GFX_WIDGETS
|
||||
bool widgets_active = video_info->widgets_active;
|
||||
#endif
|
||||
bool lcd_bottom = false;
|
||||
|
||||
if (!width || !height || !settings)
|
||||
{
|
||||
|
@ -591,12 +1133,10 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
return true;
|
||||
}
|
||||
|
||||
state_tmp = hidKeysDown();
|
||||
hidTouchRead(&state_tmp_touch);
|
||||
if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120))
|
||||
{
|
||||
ctr_set_bottom_screen_enable(ctr, !ctr_bottom_screen_enabled);
|
||||
}
|
||||
lcd_bottom = settings->bools.video_3ds_lcd_bottom;
|
||||
if (lcd_bottom != ctr_bottom_screen_enabled)
|
||||
ctr_set_bottom_screen_enable(lcd_bottom);
|
||||
bottom_menu_control(data, lcd_bottom);
|
||||
|
||||
if (ctr->p3d_event_pending)
|
||||
{
|
||||
|
@ -742,11 +1282,23 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
custom_vp_height
|
||||
);
|
||||
|
||||
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
|
||||
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
0x201, NULL, 0x00000000,
|
||||
0,
|
||||
0x201);
|
||||
if (ctr->refresh_bottom_menu)
|
||||
{
|
||||
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
|
||||
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
0x201,
|
||||
(u32*)ctr->drawbuffers.bottom, 0x00000000,
|
||||
(u32*)ctr->drawbuffers.bottom + 2 * CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
0x201);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
|
||||
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
0x201, NULL, 0x00000000,
|
||||
0,
|
||||
0x201);
|
||||
}
|
||||
|
||||
GPUCMD_SetBufferOffset(0);
|
||||
|
||||
|
@ -923,6 +1475,12 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
gfx_widgets_frame(video_info);
|
||||
#endif
|
||||
|
||||
#ifndef CONSOLE_LOG
|
||||
if (ctr_bottom_screen_enabled &&
|
||||
rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
||||
ctr_render_bottom_screen(ctr);
|
||||
#endif
|
||||
|
||||
if (msg)
|
||||
font_driver_render_msg(ctr, msg, NULL, NULL);
|
||||
|
||||
|
@ -943,10 +1501,21 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
CTRGU_RGBA8,
|
||||
gfxTopRightFramebuffers[ctr->current_buffer_top], 240, CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE);
|
||||
|
||||
#ifndef CONSOLE_LOG
|
||||
ctrGuDisplayTransfer(true,
|
||||
ctr->drawbuffers.bottom,
|
||||
240,
|
||||
320,
|
||||
CTRGU_RGBA8,
|
||||
gfxBottomFramebuffers[ctr->current_buffer_bottom],
|
||||
240,
|
||||
CTRGU_RGB8,
|
||||
CTRGU_MULTISAMPLE_NONE);
|
||||
#endif
|
||||
/* Swap buffers : */
|
||||
|
||||
#ifdef USE_CTRULIB_2
|
||||
u32 *buf0, *buf1;
|
||||
u32 *buf0, *buf1, *bottom;
|
||||
u32 stride;
|
||||
|
||||
buf0 = (u32*)gfxTopLeftFramebuffers[ctr->current_buffer_top];
|
||||
|
@ -970,6 +1539,16 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
|
||||
gspPresentBuffer(GFX_TOP, ctr->current_buffer_top, buf0, buf1,
|
||||
stride, (1<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES);
|
||||
|
||||
#ifndef CONSOLE_LOG
|
||||
if (ctr->refresh_bottom_menu)
|
||||
{
|
||||
bottom = (u32*)gfxBottomFramebuffers[ctr->current_buffer_bottom];
|
||||
stride = 240 * 3;
|
||||
gspPresentBuffer(GFX_BOTTOM, ctr->current_buffer_bottom, bottom, bottom,
|
||||
stride, GSP_BGR8_OES);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
topFramebufferInfo.
|
||||
active_framebuf = ctr->current_buffer_top;
|
||||
|
@ -990,7 +1569,7 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
framebuf1_vaddr = (u32*)gfxTopRightFramebuffers[ctr->current_buffer_top];
|
||||
else
|
||||
topFramebufferInfo.
|
||||
framebuf1_vaddr = topFramebufferInfo.framebuf0_vaddr;
|
||||
framebuf1_vaddr = topFramebufferInfo.framebuf0_vaddr;
|
||||
|
||||
topFramebufferInfo.
|
||||
framebuf_widthbytesize = 240 * 3;
|
||||
|
@ -1008,11 +1587,43 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
framebufferInfoHeader[0x0] ^= 1;
|
||||
framebufferInfo[framebufferInfoHeader[0x0]] = topFramebufferInfo;
|
||||
framebufferInfoHeader[0x1] = 1;
|
||||
|
||||
#ifndef CONSOLE_LOG
|
||||
if (ctr->refresh_bottom_menu)
|
||||
{
|
||||
bottomFramebufferInfo.
|
||||
active_framebuf = ctr->current_buffer_bottom;
|
||||
bottomFramebufferInfo.
|
||||
framebuf0_vaddr = (u32*)gfxBottomFramebuffers[
|
||||
ctr->current_buffer_bottom];
|
||||
|
||||
bottomFramebufferInfo.
|
||||
framebuf1_vaddr = (u32*)(gfxBottomFramebuffers[
|
||||
ctr->current_buffer_bottom] + 240 * 3);
|
||||
bottomFramebufferInfo.
|
||||
framebuf_widthbytesize = 240 * 3;
|
||||
|
||||
bottomFramebufferInfo.format = GSP_BGR8_OES;
|
||||
bottomFramebufferInfo.
|
||||
framebuf_dispselect = ctr->current_buffer_bottom;
|
||||
bottomFramebufferInfo.unk = 0x00000000;
|
||||
|
||||
u8* framebufferInfoHeader2 = gfxSharedMemory+0x200+gfxThreadID*0x80+0x40;
|
||||
GSPGPU_FramebufferInfo*
|
||||
framebufferInfo2 =
|
||||
(GSPGPU_FramebufferInfo*)&framebufferInfoHeader2[0x4];
|
||||
framebufferInfoHeader2[0x0] ^= 1;
|
||||
framebufferInfo2[framebufferInfoHeader2[0x0]] = bottomFramebufferInfo;
|
||||
framebufferInfoHeader2[0x1] = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ctr->current_buffer_top ^= 1;
|
||||
ctr->current_buffer_bottom ^= 1;
|
||||
ctr->p3d_event_pending = true;
|
||||
ctr->ppf_event_pending = true;
|
||||
ctr->refresh_bottom_menu = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1047,16 +1658,33 @@ static bool ctr_suppress_screensaver(void* data, bool enable)
|
|||
|
||||
static void ctr_free(void* data)
|
||||
{
|
||||
unsigned i;
|
||||
ctr_video_t* ctr = (ctr_video_t*)data;
|
||||
|
||||
if (!ctr)
|
||||
return;
|
||||
|
||||
if (ctr->state_data_on_ram)
|
||||
save_state_to_file(ctr);
|
||||
|
||||
aptUnhook(&ctr->lcd_aptHook);
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, true);
|
||||
shaderProgramFree(&ctr->shader);
|
||||
DVLB_Free(ctr->dvlb);
|
||||
vramFree(ctr->drawbuffers.top.left);
|
||||
vramFree(ctr->drawbuffers.bottom);
|
||||
for (i = 0; i < CTR_TEXTURE_LAST; i++)
|
||||
{
|
||||
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
|
||||
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
||||
if (texture)
|
||||
{
|
||||
linearFree(texture->data);
|
||||
linearFree(o->frame_coords);
|
||||
o->texture = 0;
|
||||
}
|
||||
}
|
||||
free(ctr->bottom_textures);
|
||||
linearFree(ctr->display_list);
|
||||
linearFree(ctr->texture_linear);
|
||||
linearFree(ctr->texture_swizzled);
|
||||
|
@ -1064,7 +1692,6 @@ static void ctr_free(void* data)
|
|||
linearFree(ctr->menu.texture_linear);
|
||||
linearFree(ctr->menu.texture_swizzled);
|
||||
linearFree(ctr->menu.frame_coords);
|
||||
linearFree(ctr->empty_framebuffer);
|
||||
linearFree(ctr->vertex_cache.buffer);
|
||||
linearFree(ctr);
|
||||
#if 0
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
typedef struct
|
||||
{
|
||||
ctr_texture_t texture;
|
||||
ctr_scale_vector_t scale_vector;
|
||||
ctr_scale_vector_t scale_vector_top;
|
||||
ctr_scale_vector_t scale_vector_bottom;
|
||||
const font_renderer_driver_t* font_driver;
|
||||
void* font_data;
|
||||
} ctr_font_t;
|
||||
|
@ -95,7 +96,15 @@ static void* ctr_font_init_font(void* data, const char* font_path,
|
|||
linearFree(tmp);
|
||||
#endif
|
||||
|
||||
ctr_set_scale_vector(&font->scale_vector, 400, 240, font->texture.width, font->texture.height);
|
||||
ctr_set_scale_vector(&font->scale_vector_top,
|
||||
CTR_TOP_FRAMEBUFFER_WIDTH,
|
||||
CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
font->texture.width, font->texture.height);
|
||||
|
||||
ctr_set_scale_vector(&font->scale_vector_bottom,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
|
||||
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
font->texture.width, font->texture.height);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
@ -174,11 +183,12 @@ static void ctr_font_render_line(
|
|||
switch (text_align)
|
||||
{
|
||||
case TEXT_ALIGN_RIGHT:
|
||||
x -= ctr_font_get_message_width(font, msg, msg_len, scale);
|
||||
x += width - ctr_font_get_message_width(font, msg, msg_len, scale);
|
||||
break;
|
||||
|
||||
case TEXT_ALIGN_CENTER:
|
||||
x -= ctr_font_get_message_width(font, msg, msg_len, scale) / 2;
|
||||
x += width / 2 -
|
||||
ctr_font_get_message_width(font, msg, msg_len, scale) / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -231,7 +241,11 @@ static void ctr_font_render_line(
|
|||
return;
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
||||
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector, 1);
|
||||
if (!ctr->render_font_bottom)
|
||||
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector_top, 1);
|
||||
else
|
||||
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector_bottom, 1);
|
||||
|
||||
GSPGPU_FlushDataCache(ctr->vertex_cache.current,
|
||||
(v - ctr->vertex_cache.current) * sizeof(ctr_vertex_t));
|
||||
ctrGuSetAttributeBuffers(2,
|
||||
|
@ -261,20 +275,31 @@ static void ctr_font_render_line(
|
|||
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
||||
GPU_L8);
|
||||
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
||||
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240
|
||||
? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
|
||||
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
|
||||
|
||||
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
|
||||
if (!ctr->render_font_bottom)
|
||||
{
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
|
||||
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
CTR_TOP_FRAMEBUFFER_WIDTH);
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
||||
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240
|
||||
? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
|
||||
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
|
||||
|
||||
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
|
||||
{
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
|
||||
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
||||
CTR_TOP_FRAMEBUFFER_WIDTH);
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GPU_SetViewport(NULL,
|
||||
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
|
||||
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
|
||||
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
|
||||
}
|
||||
|
||||
|
@ -363,8 +388,10 @@ static void ctr_font_render_msg(
|
|||
alpha, r_dark, g_dark, b_dark, alpha_dark;
|
||||
ctr_font_t * font = (ctr_font_t*)data;
|
||||
ctr_video_t *ctr = (ctr_video_t*)userdata;
|
||||
unsigned width = ctr->vp.full_width;
|
||||
unsigned height = ctr->vp.full_height;
|
||||
unsigned width = ctr->render_font_bottom ?
|
||||
CTR_BOTTOM_FRAMEBUFFER_WIDTH : CTR_TOP_FRAMEBUFFER_WIDTH;
|
||||
unsigned height = ctr->render_font_bottom ?
|
||||
CTR_BOTTOM_FRAMEBUFFER_HEIGHT : CTR_TOP_FRAMEBUFFER_HEIGHT;
|
||||
settings_t *settings = config_get_ptr();
|
||||
float video_msg_pos_x = settings->floats.video_msg_pos_x;
|
||||
float video_msg_pos_y = settings->floats.video_msg_pos_y;
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
static uint32_t pad_state;
|
||||
static int16_t analog_state[DEFAULT_MAX_PADS][2][2];
|
||||
|
||||
/* TODO/FIXME - global referenced outside */
|
||||
extern uint64_t lifecycle_state;
|
||||
|
||||
static const char *ctr_joypad_name(unsigned pad)
|
||||
{
|
||||
return "3DS Controller";
|
||||
|
@ -193,11 +190,6 @@ static void ctr_joypad_poll(void)
|
|||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = ctr_joypad_fix_range(state_tmp_right_analog.dx);
|
||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = -ctr_joypad_fix_range(state_tmp_right_analog.dy);
|
||||
|
||||
BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
|
||||
if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py > 120))
|
||||
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
||||
|
||||
/* panic button */
|
||||
if((state_tmp & KEY_START) &&
|
||||
(state_tmp & KEY_SELECT) &&
|
||||
|
|
|
@ -11255,6 +11255,10 @@ MSG_HASH(
|
|||
MSG_FAILED_TO_SAVE_SRAM,
|
||||
"Failed to save SRAM"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_FAILED_TO_LOAD_SRAM,
|
||||
"Failed to load SRAM"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_FAILED_TO_SAVE_STATE_TO,
|
||||
"Failed to save state to"
|
||||
|
@ -12674,6 +12678,34 @@ MSG_HASH(
|
|||
MENU_ENUM_LABEL_VALUE_CTR_VIDEO_MODE_2D_800X240,
|
||||
"2D (High Resolution)"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_DEFAULT,
|
||||
"Tap the Touch Screen to go\nto the Retroarch menu"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND,
|
||||
"bottom_menu.png not found\nin the assets/ctr folder"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_NO_STATE_DATA,
|
||||
"No\nData"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL,
|
||||
"No\nScreenshot"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_RESUME,
|
||||
"Resume Game"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_SAVE_STATE,
|
||||
"Create\nRestore Point"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_3DS_BOTTOM_MENU_LOAD_STATE,
|
||||
"Load\nRestore Point"
|
||||
)
|
||||
#endif
|
||||
#ifdef HAVE_QT
|
||||
MSG_HASH(
|
||||
|
|
|
@ -17382,8 +17382,10 @@ static bool setting_append_list(
|
|||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_CMD_APPLY_AUTO);
|
||||
#ifdef CONSOLE_LOG
|
||||
MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_REINIT_FROM_TOGGLE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
CONFIG_BOOL(
|
||||
|
|
|
@ -399,6 +399,7 @@ enum msg_hash_enums
|
|||
MSG_LOADING_STATE,
|
||||
MSG_FAILED_TO_SAVE_STATE_TO,
|
||||
MSG_FAILED_TO_SAVE_SRAM,
|
||||
MSG_FAILED_TO_LOAD_SRAM,
|
||||
MSG_STATE_SIZE,
|
||||
MSG_FAILED_TO_LOAD_CONTENT,
|
||||
MSG_COULD_NOT_READ_CONTENT_FILE,
|
||||
|
@ -3222,6 +3223,14 @@ enum msg_hash_enums
|
|||
MSG_MANUAL_CONTENT_SCAN_M3U_CLEANUP,
|
||||
MSG_MANUAL_CONTENT_SCAN_END,
|
||||
|
||||
MSG_3DS_BOTTOM_MENU_DEFAULT,
|
||||
MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND,
|
||||
MSG_3DS_BOTTOM_MENU_NO_STATE_DATA,
|
||||
MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL,
|
||||
MSG_3DS_BOTTOM_MENU_RESUME,
|
||||
MSG_3DS_BOTTOM_MENU_SAVE_STATE,
|
||||
MSG_3DS_BOTTOM_MENU_LOAD_STATE,
|
||||
|
||||
MSG_LAST,
|
||||
|
||||
/* Ensure sizeof(enum) == sizeof(int) */
|
||||
|
|
88
retroarch.c
88
retroarch.c
|
@ -7980,6 +7980,31 @@ static void path_clear_all(void)
|
|||
path_clear(RARCH_PATH_BASENAME);
|
||||
}
|
||||
|
||||
bool retroarch_get_current_savestate_path(char *path, size_t len)
|
||||
{
|
||||
struct rarch_state *p_rarch = &rarch_st;
|
||||
const global_t *global = &p_rarch->g_extern;
|
||||
settings_t *settings = p_rarch->configuration_settings;
|
||||
int state_slot = settings ? settings->ints.state_slot : 0;
|
||||
const char *name_savestate = NULL;
|
||||
|
||||
if (!path || !global)
|
||||
return false;
|
||||
|
||||
name_savestate = global->name.savestate;
|
||||
if (string_is_empty(name_savestate))
|
||||
return false;
|
||||
|
||||
if (state_slot > 0)
|
||||
snprintf(path, len, "%s%d", name_savestate, state_slot);
|
||||
else if (state_slot < 0)
|
||||
fill_pathname_join_delim(path, name_savestate, "auto", '.', len);
|
||||
else
|
||||
strlcpy(path, name_savestate, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum rarch_content_type path_is_media_type(const char *path)
|
||||
{
|
||||
char ext_lower[128];
|
||||
|
@ -11451,20 +11476,7 @@ static bool command_event_main_state(
|
|||
|
||||
state_path[0] = msg[0] = '\0';
|
||||
|
||||
if (global)
|
||||
{
|
||||
int state_slot = settings->ints.state_slot;
|
||||
const char *name_savestate = global->name.savestate;
|
||||
|
||||
if (state_slot > 0)
|
||||
snprintf(state_path, sizeof(state_path), "%s%d",
|
||||
name_savestate, state_slot);
|
||||
else if (state_slot < 0)
|
||||
fill_pathname_join_delim(state_path,
|
||||
name_savestate, "auto", '.', sizeof(state_path));
|
||||
else
|
||||
strlcpy(state_path, name_savestate, sizeof(state_path));
|
||||
}
|
||||
retroarch_get_current_savestate_path(state_path, sizeof(state_path));
|
||||
|
||||
core_serialize_size(&info);
|
||||
|
||||
|
@ -11473,6 +11485,7 @@ static bool command_event_main_state(
|
|||
switch (cmd)
|
||||
{
|
||||
case CMD_EVENT_SAVE_STATE:
|
||||
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
||||
{
|
||||
bool savestate_auto_index =
|
||||
settings->bools.savestate_auto_index;
|
||||
|
@ -11481,7 +11494,10 @@ static bool command_event_main_state(
|
|||
bool frame_time_counter_reset_after_save_state =
|
||||
settings->bools.frame_time_counter_reset_after_save_state;
|
||||
|
||||
content_save_state(state_path, true, false);
|
||||
if (cmd == CMD_EVENT_SAVE_STATE)
|
||||
content_save_state(state_path, true, false);
|
||||
else
|
||||
content_save_state_to_ram();
|
||||
|
||||
/* Clean up excess savestates if necessary */
|
||||
if (savestate_auto_index && (savestate_max_keep > 0))
|
||||
|
@ -11499,24 +11515,33 @@ static bool command_event_main_state(
|
|||
}
|
||||
break;
|
||||
case CMD_EVENT_LOAD_STATE:
|
||||
if (content_load_state(state_path, false, false))
|
||||
case CMD_EVENT_LOAD_STATE_FROM_RAM:
|
||||
{
|
||||
bool res = false;
|
||||
if (cmd == CMD_EVENT_LOAD_STATE)
|
||||
res = content_load_state(state_path, false, false);
|
||||
else
|
||||
res = content_load_state_from_ram();
|
||||
|
||||
if (res)
|
||||
{
|
||||
#ifdef HAVE_CHEEVOS
|
||||
if (rcheevos_hardcore_active())
|
||||
{
|
||||
rcheevos_pause_hardcore();
|
||||
runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
}
|
||||
if (rcheevos_hardcore_active())
|
||||
{
|
||||
rcheevos_pause_hardcore();
|
||||
runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
}
|
||||
#endif
|
||||
ret = true;
|
||||
ret = true;
|
||||
#ifdef HAVE_NETWORKING
|
||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
|
||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
|
||||
#endif
|
||||
{
|
||||
bool frame_time_counter_reset_after_load_state =
|
||||
settings->bools.frame_time_counter_reset_after_load_state;
|
||||
if (frame_time_counter_reset_after_load_state)
|
||||
p_rarch->video_driver_frame_time_count = 0;
|
||||
{
|
||||
bool frame_time_counter_reset_after_load_state =
|
||||
settings->bools.frame_time_counter_reset_after_load_state;
|
||||
if (frame_time_counter_reset_after_load_state)
|
||||
p_rarch->video_driver_frame_time_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
push_msg = false;
|
||||
|
@ -12238,11 +12263,13 @@ bool command_event(enum event_command cmd, void *data)
|
|||
return false;
|
||||
break;
|
||||
case CMD_EVENT_UNDO_LOAD_STATE:
|
||||
case CMD_EVENT_UNDO_SAVE_STATE:
|
||||
case CMD_EVENT_LOAD_STATE_FROM_RAM:
|
||||
if (!command_event_main_state(p_rarch, cmd))
|
||||
return false;
|
||||
break;
|
||||
case CMD_EVENT_UNDO_SAVE_STATE:
|
||||
if (!command_event_main_state(p_rarch, cmd))
|
||||
case CMD_EVENT_RAM_STATE_TO_FILE:
|
||||
if (!content_ram_state_to_file((char *) data))
|
||||
return false;
|
||||
break;
|
||||
case CMD_EVENT_RESIZE_WINDOWED_SCALE:
|
||||
|
@ -12274,6 +12301,7 @@ bool command_event(enum event_command cmd, void *data)
|
|||
#endif
|
||||
return false;
|
||||
case CMD_EVENT_SAVE_STATE:
|
||||
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
||||
{
|
||||
bool savestate_auto_index = settings->bools.savestate_auto_index;
|
||||
int state_slot = settings->ints.state_slot;
|
||||
|
|
|
@ -2114,6 +2114,8 @@ typedef enum apple_view_type
|
|||
APPLE_VIEW_TYPE_METAL
|
||||
} apple_view_type_t;
|
||||
|
||||
bool retroarch_get_current_savestate_path(char *path, size_t len);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -151,6 +151,10 @@ static struct save_state_buf undo_save_buf;
|
|||
* Can be restored with undo_load_state(). */
|
||||
static struct save_state_buf undo_load_buf;
|
||||
|
||||
/* Buffer that stores state instead of file.
|
||||
* This is useful for devices with slow I/O. */
|
||||
static struct save_state_buf ram_buf;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
/* TODO/FIXME - global state - perhaps move outside this file */
|
||||
static struct autosave_st autosave_state;
|
||||
|
@ -1669,6 +1673,15 @@ bool content_reset_savestate_backups(void)
|
|||
undo_load_buf.path[0] = '\0';
|
||||
undo_load_buf.size = 0;
|
||||
|
||||
if (ram_buf.data)
|
||||
{
|
||||
free(ram_buf.data);
|
||||
ram_buf.data = NULL;
|
||||
}
|
||||
|
||||
ram_buf.path[0] = '\0';
|
||||
ram_buf.size = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1808,6 +1821,148 @@ static bool dump_to_file_desperate(const void *data,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* content_load_state_from_ram:
|
||||
* Load a state from ram.
|
||||
*
|
||||
* Returns: true if successful, false otherwise.
|
||||
**/
|
||||
bool content_load_state_from_ram(void)
|
||||
{
|
||||
size_t temp_data_size;
|
||||
bool ret = false;
|
||||
void* temp_data = NULL;
|
||||
|
||||
RARCH_LOG("[State]: %s, %u %s.\n",
|
||||
msg_hash_to_str(MSG_LOADING_STATE),
|
||||
(unsigned)ram_buf.size,
|
||||
msg_hash_to_str(MSG_BYTES));
|
||||
|
||||
/* We need to make a temporary copy of the buffer, to allow the swap below */
|
||||
temp_data = malloc(ram_buf.size);
|
||||
temp_data_size = ram_buf.size;
|
||||
memcpy(temp_data, ram_buf.data, ram_buf.size);
|
||||
|
||||
/* Swap the current state with the backup state. This way, we can undo
|
||||
what we're undoing */
|
||||
content_save_state("RAM", false, false);
|
||||
|
||||
ret = content_deserialize_state(temp_data, temp_data_size);
|
||||
|
||||
/* Clean up the temporary copy */
|
||||
free(temp_data);
|
||||
temp_data = NULL;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
RARCH_ERR("[State]: %s.\n",
|
||||
msg_hash_to_str(MSG_FAILED_TO_LOAD_SRAM));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* content_save_state_from_ram:
|
||||
* Save a state to ram.
|
||||
*
|
||||
* Returns: true if successful, false otherwise.
|
||||
**/
|
||||
bool content_save_state_to_ram(void)
|
||||
{
|
||||
retro_ctx_size_info_t info;
|
||||
void *data = NULL;
|
||||
size_t serial_size;
|
||||
|
||||
core_serialize_size(&info);
|
||||
|
||||
if (info.size == 0)
|
||||
return false;
|
||||
serial_size = info.size;
|
||||
|
||||
if (!save_state_in_background)
|
||||
{
|
||||
data = content_get_serialized_data(&serial_size);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
RARCH_ERR("[State]: %s.\n",
|
||||
msg_hash_to_str(MSG_FAILED_TO_SAVE_SRAM));
|
||||
return false;
|
||||
}
|
||||
|
||||
RARCH_LOG("[State]: %s, %u %s.\n",
|
||||
msg_hash_to_str(MSG_SAVING_STATE),
|
||||
(unsigned)serial_size,
|
||||
msg_hash_to_str(MSG_BYTES));
|
||||
}
|
||||
|
||||
if (!data)
|
||||
data = content_get_serialized_data(&serial_size);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
RARCH_ERR("[State]: %s.\n",
|
||||
msg_hash_to_str(MSG_FAILED_TO_SAVE_SRAM));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If we were holding onto an old state already, clean it up first */
|
||||
if (ram_buf.data)
|
||||
{
|
||||
free(ram_buf.data);
|
||||
ram_buf.data = NULL;
|
||||
}
|
||||
|
||||
ram_buf.data = malloc(serial_size);
|
||||
if (!ram_buf.data)
|
||||
{
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(ram_buf.data, data, serial_size);
|
||||
free(data);
|
||||
ram_buf.size = serial_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* content_ram_state_to_file:
|
||||
* @path : path of ram state that shall be written to.
|
||||
* Save a ram state from memory to disk.
|
||||
*
|
||||
* Returns: true if successful, false otherwise.
|
||||
**/
|
||||
bool content_ram_state_to_file(const char *path)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
#if defined(HAVE_ZLIB)
|
||||
bool compress_files = settings->bools.save_file_compression;
|
||||
#else
|
||||
bool compress_files = false;
|
||||
#endif
|
||||
bool write_success;
|
||||
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
if (!ram_buf.data)
|
||||
return false;
|
||||
|
||||
#if defined(HAVE_ZLIB)
|
||||
if (compress_files)
|
||||
write_success = rzipstream_write_file(
|
||||
path, ram_buf.data, ram_buf.size);
|
||||
else
|
||||
#endif
|
||||
write_success = filestream_write_file(
|
||||
path, ram_buf.data, ram_buf.size);
|
||||
|
||||
return write_success;
|
||||
}
|
||||
|
||||
/**
|
||||
* content_save_ram_file:
|
||||
* @path : path of RAM state that shall be written to.
|
||||
|
|
Loading…
Reference in a new issue