diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c
index 2fcc042c7a..541967ecbc 100644
--- a/gfx/common/win32_common.c
+++ b/gfx/common/win32_common.c
@@ -30,6 +30,35 @@
#include "../drivers_wm/win32_shader_dlg.h"
#endif
+#ifndef _XBOX
+/* Power Request APIs */
+
+typedef REASON_CONTEXT POWER_REQUEST_CONTEXT, *PPOWER_REQUEST_CONTEXT, *LPPOWER_REQUEST_CONTEXT;
+
+WINBASEAPI
+HANDLE
+WINAPI
+PowerCreateRequest (
+ PREASON_CONTEXT Context
+ );
+
+WINBASEAPI
+BOOL
+WINAPI
+PowerSetRequest (
+ HANDLE PowerRequest,
+ POWER_REQUEST_TYPE RequestType
+ );
+
+WINBASEAPI
+BOOL
+WINAPI
+PowerClearRequest (
+ HANDLE PowerRequest,
+ POWER_REQUEST_TYPE RequestType
+ );
+#endif
+
static bool win32_browser(
HWND owner,
char *filename,
@@ -239,3 +268,42 @@ void win32_check_window(void)
}
#endif
}
+
+bool win32_suppress_screensaver(void *data, bool enable)
+{
+#ifdef _XBOX
+ return false;
+#else
+ typedef HANDLE (WINAPI * PowerCreateRequestPtr)(REASON_CONTEXT *context);
+ HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
+ PowerCreateRequestPtr powerCreateRequest =
+ (PowerCreateRequestPtr)GetProcAddress(kernel32, "PowerCreateRequest");
+
+ if(enable)
+ {
+ if(powerCreateRequest)
+ {
+ /* Windows 7, 8, 10 codepath */
+ POWER_REQUEST_CONTEXT RequestContext;
+ HANDLE Request;
+
+ RequestContext.Version = POWER_REQUEST_CONTEXT_VERSION;
+ RequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
+ RequestContext.Reason.SimpleReasonString = L"RetroArch running";
+
+ Request = PowerCreateRequest(&RequestContext);
+
+ PowerSetRequest( Request, PowerRequestDisplayRequired);
+ return true;
+ }
+ else
+ {
+ /* XP / Vista codepath */
+ SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED);
+ return true;
+ }
+ }
+
+ return false;
+#endif
+}
diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h
index fa7a978366..70322081a6 100644
--- a/gfx/common/win32_common.h
+++ b/gfx/common/win32_common.h
@@ -37,6 +37,8 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message,
LRESULT win32_menu_loop(HWND handle, WPARAM wparam);
#endif
+bool win32_suppress_screensaver(void *data, bool enable);
+
bool win32_get_metrics(void *data,
enum display_metric_types type, float *value);
diff --git a/gfx/drivers_context/d3d_ctx.cpp b/gfx/drivers_context/d3d_ctx.cpp
index 493510ce47..005e5bcfe9 100644
--- a/gfx/drivers_context/d3d_ctx.cpp
+++ b/gfx/drivers_context/d3d_ctx.cpp
@@ -206,10 +206,7 @@ static bool gfx_ctx_d3d_has_focus(void *data)
static bool gfx_ctx_d3d_suppress_screensaver(void *data, bool enable)
{
- (void)data;
- (void)enable;
-
- return false;
+ return win32_suppress_screensaver(data, enable);
}
static bool gfx_ctx_d3d_has_windowed(void *data)
diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c
index 03c331c05b..26d3606a0b 100644
--- a/gfx/drivers_context/wgl_ctx.c
+++ b/gfx/drivers_context/wgl_ctx.c
@@ -640,10 +640,7 @@ static bool gfx_ctx_wgl_has_focus(void *data)
static bool gfx_ctx_wgl_suppress_screensaver(void *data, bool enable)
{
- (void)data;
- (void)enable;
-
- return false;
+ return win32_suppress_screensaver(data, enable);
}
static bool gfx_ctx_wgl_has_windowed(void *data)
diff --git a/menu/driverspzarch.c b/menu/driverspzarch.c
new file mode 100644
index 0000000000..d258a35b07
--- /dev/null
+++ b/menu/driverspzarch.c
@@ -0,0 +1,1262 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2011-2015 - Daniel De Matteis
+ * Copyright (C) 2014-2015 - Jean-André Santoni
+ *
+ * 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 "menu_generic.h"
+
+#include "../../config.def.h"
+
+#include "../menu.h"
+#include "../menu_animation.h"
+#include "../menu_entry.h"
+#include "../menu_display.h"
+#include "../../runloop_data.h"
+
+#include "../../gfx/video_thread_wrapper.h"
+#include "../../gfx/font_driver.h"
+#include "../../gfx/video_texture.h"
+#include "../menu_video.h"
+
+const GLfloat ZUI_NORMAL[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+};
+const GLfloat ZUI_HILITE[] = {
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+};
+const GLfloat ZUI_PRESS[] = {
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+};
+const GLfloat ZUI_BARBG[] = {
+ 0, 0, 1, 1,
+ 0, 0, 1, 1,
+ 0, 0, 1, 1,
+ 0, 0, 1, 1,
+};
+
+const uint32_t ZUI_FG_NORMAL = ~0;
+const GLfloat ZUI_BG_PANEL[] = {
+ 0, 0, 0, 0.25,
+ 0, 0, 0, 0.25,
+ 0, 0, 0, 0.25,
+ 0, 0, 0, 0.25,
+};
+const GLfloat ZUI_BG_SCREEN[] = {
+ 0.07, 0.19, 0.26, 1,
+ 0.07, 0.19, 0.26, 1,
+ 0.15, 0.31, 0.47, 1,
+ 0.15, 0.31, 0.47, 1,
+};
+const GLfloat ZUI_BG_HILITE[] = {
+ 0.22, 0.60, 0.74, 1,
+ 0.22, 0.60, 0.74, 1,
+ 0.22, 0.60, 0.74, 1,
+ 0.22, 0.60, 0.74, 1,
+};
+
+
+typedef struct zarch_handle
+{
+ bool rendering;
+ settings_t *set;
+ menu_handle_t *menu;
+ math_matrix_4x4 mvp;
+ unsigned width;
+ unsigned height;
+ gfx_font_raster_block_t tmp_block;
+ unsigned hash;
+ bool time_to_exit;
+
+ struct {
+ unsigned active;
+ unsigned hot;
+ } item;
+
+ gfx_coord_array_t ca;
+
+ struct
+ {
+ int16_t x;
+ int16_t y;
+ bool left;
+ bool right;
+ bool oldleft;
+ bool oldright;
+ int wheel;
+ } mouse;
+
+ /* LAY_ROOT's "Load" file browser */
+ struct string_list *load_dlist;
+ char *load_cwd;
+ int load_dlist_first;
+
+ struct
+ {
+ struct
+ {
+ GRuint id;
+ char path[PATH_MAX_LENGTH];
+ } bg;
+ GRuint white;
+ } textures;
+
+ /* LAY_PICK_CORE */
+ int pick_first;
+ char pick_content[PATH_MAX_LENGTH];
+ const core_info_t *pick_cores;
+ size_t pick_supported;
+
+ void *fb_buf;
+ int font_size;
+ int header_height;
+} zui_t;
+
+typedef struct
+{
+ unsigned active;
+ int x, y;
+ int width;
+ int height; /* unused */
+ int tabline_size;
+ bool update_width;
+ bool vertical;
+ int tab_width;
+} zui_tabbed_t;
+
+typedef struct
+{
+ float x, y;
+ float xspeed, yspeed;
+ float alpha;
+ bool alive;
+} part_t;
+
+static enum
+{
+ LAY_HOME,
+ LAY_PICK_CORE,
+ LAY_SETTINGS
+} layout = LAY_HOME;
+
+static const GRfloat zarch_vertexes[] = {
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+};
+
+static const GRfloat zarch_tex_coords[] = {
+ 0, 1,
+ 1, 1,
+ 0, 0,
+ 1, 0
+};
+
+static void zui_font(menu_handle_t *menu)
+{
+ int font_size;
+ char mediapath[PATH_MAX_LENGTH], fontpath[PATH_MAX_LENGTH];
+ settings_t *settings = config_get_ptr();
+
+ menu_display_ctl(MENU_DISPLAY_CTL_FONT_SIZE, &font_size);
+
+ fill_pathname_join(mediapath, settings->assets_directory, "zarch", sizeof(mediapath));
+ fill_pathname_join(fontpath, mediapath, "Roboto-Condensed.ttf", sizeof(fontpath));
+
+ if (!menu_display_init_main_font(menu, fontpath, font_size))
+ RARCH_WARN("Failed to load font.");
+}
+
+static float zui_strwidth(void *fb_buf, const char *text, float scale)
+{
+ driver_t *driver = (driver_t*)driver_get_ptr();
+ return driver->font_osd_driver->get_message_width(fb_buf, text, strlen(text), scale);
+}
+
+static void zui_begin(void)
+{
+ const struct retro_keybind *binds[MAX_USERS];
+ gl_t *gl = NULL;
+ driver_t *driver = (driver_t*)driver_get_ptr();
+ menu_handle_t *menu = menu_driver_get_ptr();
+ zui_t *zui = NULL;
+
+ if (!menu)
+ return;
+
+ zui = (zui_t*)menu->userdata;
+
+ if (!zui)
+ return;
+ if (!driver)
+ return;
+
+ gl = (gl_t*)video_driver_get_ptr(NULL);
+
+ if (!gl)
+ return;
+
+ zui->rendering = true;
+
+ zui->hash = 0;
+ zui->item.hot = 0;
+
+ glViewport(0, 0, zui->width, zui->height);
+
+
+ if (gl && gl->shader && gl->shader->set_mvp)
+ gl->shader->set_mvp(gl, &zui->mvp);
+
+
+ /* why do i need this? */
+ zui->mouse.left = input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
+ zui->mouse.right = input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT);
+ zui->mouse.wheel = input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELDOWN) -
+ input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELUP);
+
+#if 1
+ zui->mouse.x = input_driver_state(binds, 0, RARCH_DEVICE_MOUSE_SCREEN, 0, RETRO_DEVICE_ID_MOUSE_X);
+ zui->mouse.y = input_driver_state(binds, 0, RARCH_DEVICE_MOUSE_SCREEN, 0, RETRO_DEVICE_ID_MOUSE_Y);
+#else
+ dx = input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
+ dy = input_driver_state(binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
+
+ zui->mouse.x += dx;
+ zui->mouse.y += dy;
+#endif
+
+ zui->ca.coords.vertices = 0;
+
+ zui->tmp_block.carr.coords.vertices = 0;
+ menu_display_font_bind_block(zui->menu, driver->font_osd_driver, &zui->tmp_block);
+
+
+}
+
+static void zui_finish(zui_t *zui,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ bool blend,
+ GLuint texture)
+{
+ driver_t *driver = (driver_t*)driver_get_ptr();
+ gl_t *gl = (gl_t*)video_driver_get_ptr(NULL);
+
+ if (!gl)
+ return;
+
+ if (!zui->mouse.left)
+ zui->item.active = 0;
+ else if (zui->item.active == 0)
+ zui->item.active = -1;
+
+ glViewport(x, y, width, height);
+ //glBindTexture(GL_TEXTURE_2D, texture);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ gl->shader->set_coords(&zui->ca);
+
+ glEnable(GL_BLEND);
+ glDrawArrays(GL_TRIANGLES, 0, zui->ca.coords.vertices);
+
+ menu_display_font_flush_block(zui->menu, driver->font_osd_driver);
+
+ glDisable(GL_BLEND);
+
+ gl->shader->set_mvp(gl, &gl->mvp_no_rot);
+
+ zui->rendering = false;
+}
+
+static bool check_hit(zui_t *zui, int x1, int y1, int x2, int y2)
+{
+ unsigned mx = zui->mouse.x;
+ unsigned my = zui->mouse.y;
+
+ return ((mx >= x1) && (mx <= x2) && (my >= y1) && (my <= y2));
+}
+
+static bool mouse_down(zui_t *zui)
+{
+ return zui->mouse.left;
+}
+
+static bool mouse_up(zui_t *zui)
+{
+ return !mouse_down(zui);
+}
+
+static bool check_button_down(zui_t *zui, unsigned id, int x1, int y1, int x2, int y2)
+{
+ bool result = false;
+ bool inside = check_hit(zui, x1, y1, x2, y2);
+
+ if (inside)
+ zui->item.hot = id;
+
+ if (zui->item.hot == id && mouse_down(zui))
+ {
+ result = true;
+ zui->item.active = id;
+ }
+
+ return result;
+}
+
+static bool check_button_up(zui_t *zui, unsigned id, int x1, int y1, int x2, int y2)
+{
+ bool result = false;
+ bool inside = check_hit(zui, x1, y1, x2, y2);
+
+ if (inside)
+ zui->item.hot = id;
+
+ if (zui->item.active == id && mouse_up(zui))
+ {
+ if (zui->item.hot == id)
+ result = true;
+
+ zui->item.active = 0;
+ }
+
+ check_button_down(zui, id, x1, y1, x2, y2);
+
+ return result;
+}
+
+static unsigned zui_hash(zui_t *zui, const char *s)
+{
+ unsigned hval = zui->hash;
+
+ while(*s!=0)
+ {
+ hval+=*s++;
+ hval+=(hval<<10);
+ hval^=(hval>>6);
+ hval+=(hval<<3);
+ hval^=(hval>>11);
+ hval+=(hval<<15);
+ }
+ return zui->hash = hval;
+}
+
+#if 0
+static uint32_t zui_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+{
+ return FONT_COLOR_RGBA(r, g, b, a);
+}
+#endif
+
+static void zui_draw_text(zui_t *zui, uint32_t color, int x, int y, const char *text)
+{
+ struct font_params params = {0};
+
+ /* need to use height-y because the gl font renderer uses a different mvp */
+ params.x = x / (float)zui->width;
+ params.y = (zui->height - y) / (float)zui->height;
+ params.scale = 1.0;
+ params.color = color;
+ params.full_screen = true;
+ params.text_align = TEXT_ALIGN_LEFT;
+
+ video_driver_set_osd_msg(text, ¶ms, zui->fb_buf);
+}
+
+static void zui_push_quad(zui_t *zui, const GLfloat *colors, int x1, int y1,
+ int x2, int y2)
+{
+ gfx_coords_t coords;
+ GLfloat vertex[8];
+ GLfloat tex_coord[8];
+
+ tex_coord[0] = 0;
+ tex_coord[1] = 1;
+ tex_coord[2] = 1;
+ tex_coord[3] = 1;
+ tex_coord[4] = 0;
+ tex_coord[5] = 0;
+ tex_coord[6] = 1;
+ tex_coord[7] = 0;
+
+ vertex[0] = x1 / (float)zui->width;
+ vertex[1] = y1 / (float)zui->height;
+ vertex[2] = x2 / (float)zui->width;
+ vertex[3] = y1 / (float)zui->height;
+ vertex[4] = x1 / (float)zui->width;
+ vertex[5] = y2 / (float)zui->height;
+ vertex[6] = x2 / (float)zui->width;
+ vertex[7] = y2 / (float)zui->height;
+
+ coords.color = colors;
+ coords.vertex = vertex;
+ coords.tex_coord = tex_coord;
+ coords.lut_tex_coord = tex_coord;
+ coords.vertices = 3;
+
+ gfx_coord_array_add(&zui->ca, &coords, 3);
+
+ coords.color += 4;
+ coords.vertex += 2;
+ coords.tex_coord += 2;
+ coords.lut_tex_coord += 2;
+
+ gfx_coord_array_add(&zui->ca, &coords, 3);
+}
+
+static float randf(float min, float max)
+{
+ return (rand() * ((max - min) / RAND_MAX)) + min;
+}
+
+static float scalef(float val, float oldmin, float oldmax, float newmin, float newmax)
+{
+ return (((val - oldmin) * (newmax - newmin)) / (oldmax - oldmin)) + newmin;
+}
+
+#define NPARTICLES 100
+
+static void zui_snow(zui_t *zui)
+{
+ static part_t particles[NPARTICLES];
+ static bool initialized = false;
+ static int timeout = 0;
+ unsigned i, j, max_gen = 2;
+
+ if (!initialized)
+ {
+ memset(particles, 0, sizeof(particles));
+ initialized = true;
+ }
+
+ for (i = 0; i < NPARTICLES; ++i)
+ {
+ part_t *p = &particles[i];
+
+ if (p->alive)
+ {
+ p->y += p->yspeed;
+ p->x += scalef(zui->mouse.x, 0, zui->width, -0.3, 0.3) + p->xspeed;
+
+ p->alive = p->y >= 0 && p->y < (int)zui->height && p->x >= 0 && p->x < (int)zui->width;
+ }
+ else if (max_gen > 0 && timeout <= 0)
+ {
+ p->xspeed = randf(-0.2, 0.2);
+ p->yspeed = randf(1, 2);
+ p->y = 0;
+ p->x = rand() % (int)zui->width;
+ p->alpha = (float)rand() / (float)RAND_MAX;
+ p->alive = true;
+
+ max_gen--;
+ }
+ }
+
+ if (max_gen == 0)
+ timeout = 3;
+ else
+ timeout--;
+
+ j = 0;
+
+ for (i = 0; i < NPARTICLES; ++i)
+ {
+ part_t *p = &particles[i];
+
+ if (!p->alive)
+ continue;
+
+ GLfloat alpha = randf(0, 100) > 90 ? p->alpha/2 : p->alpha;
+ GLfloat colors[] = {
+ 1, 1, 1, alpha,
+ 1, 1, 1, alpha,
+ 1, 1, 1, alpha,
+ 1, 1, 1, alpha,
+ };
+
+ zui_push_quad(zui, colors, p->x-2, p->y-2, p->x+2, p->y+2);
+
+ j++;
+ }
+}
+
+static bool zui_button_full(zui_t *zui, int x1, int y1, int x2, int y2, const char *label)
+{
+ unsigned id = zui_hash(zui, label);
+#if 0
+ int x2 = x1 + zui_strwidth(zui->fb_buf, label, 1.0) + 16;
+#endif
+ bool active = check_button_up(zui, id, x1, y1, x2, y2);
+ const GLfloat *bg = ZUI_BG_PANEL;
+
+ if (zui->item.active == id || zui->item.hot == id)
+ bg = ZUI_BG_HILITE;
+
+ zui_push_quad(zui, bg, x1, y1, x2, y2);
+ zui_draw_text(zui, ZUI_FG_NORMAL, x1+12, y1 + 41, label);
+
+ return active;
+}
+
+static bool zui_button(zui_t *zui, int x1, int y1, const char *label)
+{
+ return zui_button_full(zui, x1, y1, x1 + zui_strwidth(zui->fb_buf, label, 1.0) + 24, y1 + 64, label);
+}
+
+static bool zui_list_item(zui_t *zui, int x1, int y1, const char *label)
+{
+ char title_buf[PATH_MAX_LENGTH];
+ unsigned ticker_size;
+ unsigned id = zui_hash(zui, label);
+ int x2 = x1 + zui->width - 290 - 40;
+ int y2 = y1 + 50;
+ bool active = check_button_up(zui, id, x1, y1, x2, y2);
+ const GLfloat *bg = ZUI_BG_PANEL;
+ uint64_t *frame_count = video_driver_get_frame_count();
+
+ if (zui->item.active == id || zui->item.hot == id)
+ bg = ZUI_BG_HILITE;
+
+ zui_push_quad(zui, bg, x1, y1, x2, y2);
+
+ ticker_size = x2 / 14;
+
+ menu_animation_ticker_str(title_buf,
+ ticker_size,
+ *frame_count / 50,
+ label,
+ (bg == ZUI_BG_HILITE));
+
+ zui_draw_text(zui, ZUI_FG_NORMAL, 12, y1 + 35, title_buf);
+
+ return active;
+}
+
+static void zui_tabbed_begin(zui_t *zui, zui_tabbed_t *tab, int x, int y)
+{
+ tab->x = x;
+ tab->y = y;
+ tab->tabline_size = 60 + 4;
+}
+
+static bool zui_tab(zui_t *zui, zui_tabbed_t *tab, const char *label)
+{
+ bool active;
+ int x1, y1, x2, y2;
+ unsigned id = zui_hash(zui, label);
+ int width = tab->tab_width;
+ const GLfloat *bg = ZUI_BG_PANEL;
+
+ if (!width)
+ width = zui_strwidth(zui->fb_buf, label, 1.0) + 24;
+
+ x1 = tab->x;
+ y1 = tab->y;
+ x2 = x1 + width;
+ y2 = y1 + 60;
+
+ active = check_button_up(zui, id, x1, y1, x2, y2);
+
+ if (zui->item.active == id || tab->active == ~0)
+ tab->active = id;
+
+ if (tab->active == id || zui->item.active == id || zui->item.hot == id)
+ bg = ZUI_BG_HILITE;
+
+ zui_push_quad(zui, bg, x1+0, y1+0, x2, y2);
+ zui_draw_text(zui, ZUI_FG_NORMAL, x1+12, y1 + 41, label);
+
+ if (tab->vertical)
+ tab->y += y2 - y1;
+ else
+ tab->x = x2;
+
+ return (active || (tab->active == id));
+}
+
+
+static void render_lay_settings(zui_t *zui)
+{
+ int width, x1, y1;
+ static zui_tabbed_t tabbed = {~0};
+ tabbed.vertical = true;
+ tabbed.tab_width = 100;
+
+ zui_tabbed_begin(zui, &tabbed, zui->width - 100, 20);
+
+ width = 290;
+ x1 = zui->width - width - 20;
+ y1 = 20;
+
+ y1 += 64;
+
+ if (zui_button_full(zui, x1, y1, x1 + width, y1 + 64, "Back"))
+ layout = LAY_HOME;
+}
+
+static void render_lay_root(zui_t *zui)
+{
+ static zui_tabbed_t tabbed = {~0};
+ global_t *global = global_get_ptr();
+
+ zui_tabbed_begin(zui, &tabbed, 0, 0);
+
+ tabbed.width = zui->width - 290 - 40;
+
+ if (zui_tab(zui, &tabbed, "Recent"))
+ {
+ unsigned size = min(zui->height/30-2, content_playlist_size(g_defaults.history));
+ unsigned i = 0;
+
+ for (i = 0; i < size; ++i)
+ {
+ const char *path = NULL;
+ const char *label = NULL;
+ const char *core_name = NULL;
+ const char *crc32 = NULL;
+
+ content_playlist_get_index(g_defaults.history, i,
+ &path, &label, NULL, &core_name, &crc32, NULL);
+
+ if (!label)
+ {
+ if (path)
+ label = path_basename(path);
+ else
+ label = core_name;
+ }
+
+ if (zui_list_item(zui, 0, tabbed.tabline_size + i * 54, label))
+ {
+ RARCH_LOG("Gets here, label: %s, path: %s.\n", core_name, path);
+ }
+ }
+ }
+
+ if (zui_tab(zui, &tabbed, "Load"))
+ {
+ unsigned cwd_offset;
+
+ if (!zui->load_cwd)
+ {
+ zui->load_cwd = strdup(zui->set->menu_content_directory);
+ if (zui->load_cwd[strlen(zui->load_cwd)-1] == '/'
+#ifdef _WIN32
+ || (zui->load_cwd[strlen(zui->load_cwd)-1] == '\\')
+#endif
+ )
+ zui->load_cwd[strlen(zui->load_cwd)-1] = 0;
+ }
+
+ if (!zui->load_dlist)
+ {
+ zui->load_dlist = dir_list_new(zui->load_cwd, global->core_info.current->supported_extensions, true, true);
+ dir_list_sort(zui->load_dlist, true);
+ zui->load_dlist_first = 0;
+ }
+
+ cwd_offset = min(strlen(zui->load_cwd), 30);
+
+ zui_draw_text(zui, ZUI_FG_NORMAL, 15, tabbed.tabline_size + 5 + 41, &zui->load_cwd[strlen(zui->load_cwd) - cwd_offset]);
+
+ if (zui_button(zui, zui->width - 290 - 129, tabbed.tabline_size + 5, "Home"))
+ {
+ char tmp[PATH_MAX_LENGTH];
+
+ fill_pathname_expand_special(tmp, "~", sizeof(tmp));
+
+ free(zui->load_cwd);
+ zui->load_cwd = strdup(tmp);
+
+ dir_list_free(zui->load_dlist);
+ zui->load_dlist = NULL;
+ }
+
+ if (zui->load_dlist)
+ {
+ if (zui_list_item(zui, 0, tabbed.tabline_size + 73, "^ .."))
+ {
+ path_basedir(zui->load_cwd);
+ if (zui->load_cwd[strlen(zui->load_cwd)-1] == '/'
+#ifdef _WIN32
+ || (zui->load_cwd[strlen(zui->load_cwd)-1] == '\\')
+#endif
+ )
+ zui->load_cwd[strlen(zui->load_cwd)-1] = 0;
+
+ dir_list_free(zui->load_dlist);
+ zui->load_dlist = NULL;
+ }
+ else
+ {
+ unsigned size = zui->load_dlist->size;
+ unsigned i, j = 1;
+
+ unsigned skip = 0;
+ for (i = 0; i < size; ++i)
+ {
+ const char *basename = path_basename(zui->load_dlist->elems[i].data);
+ if (basename[0] == '.')
+ skip++;
+ else
+ break;
+ }
+
+ zui->load_dlist_first += zui->mouse.wheel;
+
+ if (zui->load_dlist_first < 0)
+ zui->load_dlist_first = 0;
+ else if (zui->load_dlist_first > size - 5)
+ zui->load_dlist_first = size - 5;
+
+ zui->load_dlist_first = min(max(zui->load_dlist_first, 0), size - 5 - skip);
+
+ for (i = skip + zui->load_dlist_first; i < size; ++i)
+ {
+ char label[PATH_MAX_LENGTH];
+ const char *path = NULL;
+ const char *basename = NULL;
+
+ if (j > 10)
+ break;
+
+ path = zui->load_dlist->elems[i].data;
+ basename = path_basename(path);
+
+ *label = 0;
+ strncat(label, " ", sizeof(label)-1);
+ strncat(label, basename, sizeof(label)-1);
+
+ if (path_is_directory(path))
+ strncat(label, "/", sizeof(label)-1);
+
+ if (zui_list_item(zui, 0, tabbed.tabline_size + 73 + j * 54, label))
+ {
+ if (path_is_directory(path))
+ {
+ free(zui->load_cwd);
+ zui->load_cwd = strdup(path);
+ dir_list_free(zui->load_dlist);
+ zui->load_dlist = NULL;
+ break;
+ }
+ else
+ {
+ zui->pick_cores = NULL;
+ zui->pick_supported = 0;
+ strncpy(zui->pick_content, path, sizeof(zui->pick_content)-1);
+ core_info_list_get_supported_cores(global->core_info.list, path,
+ &zui->pick_cores, &zui->pick_supported);
+ layout = LAY_PICK_CORE;
+ break;
+ }
+ }
+ j++;
+ }
+ }
+ }
+ }
+ else if (zui->load_dlist)
+ {
+ dir_list_free(zui->load_dlist);
+ zui->load_dlist = NULL;
+ }
+
+ if (zui_tab(zui, &tabbed, "Collections"))
+ {
+ /* STUB/FIXME */
+ }
+
+ if (zui_tab(zui, &tabbed, "Download"))
+ {
+ /* STUB/FIXME */
+ }
+
+
+ zui_push_quad(zui, ZUI_BG_HILITE, 0, 60, zui->width - 290 - 40, 60+4);
+}
+
+void render_sidebar(zui_t *zui)
+{
+ int width, x1, y1;
+ static zui_tabbed_t tabbed = {~0};
+ tabbed.vertical = true;
+ tabbed.tab_width = 100;
+
+ zui_tabbed_begin(zui, &tabbed, zui->width - 100, 20);
+
+ width = 290;
+ x1 = zui->width - width - 20;
+ y1 = 20;
+
+ if (zui_button_full(zui, x1, y1, x1 + width, y1 + 64, "Settings"))
+ layout = LAY_SETTINGS;
+
+ y1 += 64;
+
+ if (zui_button_full(zui, x1, y1, x1 + width, y1 + 64, "Exit"))
+ exit(0);
+}
+
+static int zui_load_content(zui_t *zui, unsigned i)
+{
+ int ret = menu_common_load_content(zui->pick_cores[i].path,
+ zui->pick_content, false, CORE_TYPE_PLAIN);
+
+ layout = LAY_HOME;
+
+ return ret;
+}
+
+static void zui_render(void)
+{
+ menu_handle_t *menu = menu_driver_get_ptr();
+ zui_t *zui = NULL;
+
+ if (!menu)
+ return;
+
+ zui = (zui_t*)menu->userdata;
+
+ if (!zui || zui->rendering)
+ return;
+
+ zui_begin();
+
+ zui_push_quad(zui, ZUI_BG_SCREEN, 0, 0, zui->width, zui->height);
+ zui_snow(zui);
+
+
+ switch (layout)
+ {
+ case LAY_HOME:
+ render_sidebar(zui);
+ render_lay_root(zui);
+ break;
+ case LAY_SETTINGS:
+ render_lay_settings(zui);
+ break;
+ case LAY_PICK_CORE:
+ render_sidebar(zui);
+ if (zui->pick_supported == 1)
+ {
+ int ret =zui_load_content(zui, 0);
+
+ (void)ret;
+
+ layout = LAY_HOME;
+ zui->time_to_exit = true;
+ return;
+ }
+ else
+ {
+ zui_draw_text(zui, ~0, 8, 18, "Select a core: ");
+
+ if (zui_button(zui, 0, 18 + zui->font_size, "<- Back"))
+ layout = LAY_HOME;
+
+ if (zui->pick_supported)
+ {
+ unsigned i, j = 0;
+ zui->pick_first += zui->mouse.wheel;
+ zui->pick_first = min(max(zui->pick_first, 0), zui->pick_supported - 5);
+
+ for (i = zui->pick_first; i < zui->pick_supported; ++i)
+ {
+ if (j > 10)
+ break;
+
+ if (zui_list_item(zui, 0, 54 + j * 54, zui->pick_cores[i].display_name))
+ {
+ int ret =zui_load_content(zui, i);
+
+ (void)ret;
+
+ layout = LAY_HOME;
+
+ zui->time_to_exit = true;
+ break;
+ }
+ j++;
+ }
+ }
+ else
+ {
+ zui_list_item(zui, 0, 54, "Content unsupported");
+ }
+ }
+ break;
+ }
+
+ zui_finish(zui, 0, 0, zui->width, zui->height, true, zui->textures.white);
+}
+
+static void zarch_draw_cursor(gl_t *gl, float x, float y)
+{
+#if 0
+ zarch_render_quad(gl, x-5, y-5, 10, 10, 1, 1, 1, 1);
+#endif
+}
+static void zarch_get_message(const char *message)
+{
+
+}
+
+static void zarch_render(void)
+{
+ int bottom;
+ unsigned width, height;
+ zui_t *zarch = NULL;
+ menu_handle_t *menu = menu_driver_get_ptr();
+ settings_t *settings = config_get_ptr();
+
+ if (!menu || !menu->userdata)
+ return;
+
+ (void)settings;
+ (void)bottom;
+ (void)zarch;
+
+ video_driver_get_size(&width, &height);
+
+}
+
+static void zarch_frame(void)
+{
+ unsigned i;
+ GRfloat coord_color[16];
+ GRfloat coord_color2[16];
+ driver_t *driver = driver_get_ptr();
+ settings_t *settings = config_get_ptr();
+ menu_handle_t *menu = menu_driver_get_ptr();
+ zui_t *zui = NULL;
+ gl_t *gl = NULL;
+
+ if (!menu)
+ return;
+
+ gl = (gl_t*)video_driver_get_ptr(NULL);
+
+ if (!gl)
+ return;
+
+ (void)driver;
+
+ zui = (zui_t*)menu->userdata;
+ zui->set = config_get_ptr();
+ zui->menu = menu;
+
+ video_driver_get_size(&zui->width, &zui->height);
+
+ menu_display_ctl(MENU_DISPLAY_CTL_SET_VIEWPORT, NULL);
+ menu_display_ctl(MENU_DISPLAY_CTL_FONT_BUF, &zui->fb_buf);
+
+ for (i = 0; i < 16; i++)
+ {
+ coord_color[i] = 0;
+ coord_color2[i] = 2.0f;
+
+ if (i == 3 || i == 7 || i == 11 || i == 15)
+ {
+ coord_color[i] = 0.10f;
+ coord_color2[i] = 0.10f;
+ }
+ }
+ zui_render();
+
+ /* fetch it again in case the pointer was invalidated by a core load */
+ gl = (gl_t*)video_driver_get_ptr(NULL);
+
+ if (zui->set->menu.mouse.enable)
+ zarch_draw_cursor(gl, zui->mouse.x, zui->mouse.y);
+
+ menu_video_frame_background(menu, settings,
+ gl, zui->width, zui->height,
+ zui->textures.bg.id, 0.75f, false,
+ &coord_color[0], &coord_color2[0],
+ &zarch_vertexes[0], &zarch_tex_coords[0]);
+
+ if (gl && gl->shader && gl->shader->use)
+ gl->shader->use(gl, GL_SHADER_STOCK_BLEND);
+
+ menu_display_ctl(MENU_DISPLAY_CTL_UNSET_VIEWPORT, NULL);
+}
+
+static void *zarch_init(void)
+{
+ int tmpi;
+ zui_t *zui = NULL;
+ const video_driver_t *video_driver = NULL;
+ menu_handle_t *menu = NULL;
+ settings_t *settings = config_get_ptr();
+ gl_t *gl = (gl_t*)
+ video_driver_get_ptr(&video_driver);
+
+ if (video_driver != &video_gl || !gl)
+ {
+ RARCH_ERR("Cannot initialize GLUI menu driver: gl video driver is not active.\n");
+ return NULL;
+ }
+
+ if (settings->menu.mouse.enable)
+ {
+ RARCH_WARN("Forcing menu_mouse_enable=false\n");
+ settings->menu.mouse.enable = false;
+ }
+
+ menu = (menu_handle_t*)calloc(1, sizeof(*menu));
+
+ if (!menu)
+ goto error;
+
+ menu->userdata = (zui_t*)calloc(1, sizeof(zui_t));
+
+ if (!menu->userdata)
+ goto error;
+
+ zui = (zui_t*)menu->userdata;
+
+ tmpi = 1000;
+ menu_display_ctl(MENU_DISPLAY_CTL_SET_HEADER_HEIGHT, &tmpi);
+
+ tmpi = 28;
+ menu_display_ctl(MENU_DISPLAY_CTL_SET_FONT_SIZE, &tmpi);
+
+ zui->header_height = 1000; /* dpi / 3; */
+ zui->font_size = 28;
+
+ if (settings->menu.wallpaper[0] != '\0')
+ rarch_main_data_msg_queue_push(DATA_TYPE_IMAGE,
+ settings->menu.wallpaper, "cb_menu_wallpaper", 0, 1, true);
+
+ zui->ca.allocated = 0;
+
+ matrix_4x4_ortho(&zui->mvp, 0, 1, 1, 0, 0, 1);
+
+ zui_font(menu);
+
+ return menu;
+error:
+ if (menu)
+ free(menu);
+ return NULL;
+}
+
+static void zarch_free(void *data)
+{
+ gl_t *gl = NULL;
+ const struct font_renderer *font_driver = NULL;
+ menu_handle_t *menu = (menu_handle_t*)data;
+ driver_t *driver = driver_get_ptr();
+ zui_t *zarch = (zui_t*)menu->userdata;
+
+ if (!zarch || !menu)
+ return;
+
+ gfx_coord_array_free(&zarch->tmp_block.carr);
+
+ gl = (gl_t*)video_driver_get_ptr(NULL);
+
+ font_driver = gl ? (const struct font_renderer*)driver->font_osd_driver : NULL;
+
+ if (font_driver && font_driver->bind_block)
+ font_driver->bind_block(driver->font_osd_data, NULL);
+
+ if (menu->userdata)
+ free(menu->userdata);
+}
+
+static void zarch_context_bg_destroy(zui_t *zarch)
+{
+}
+
+static void zarch_context_destroy(void)
+{
+ gl_t *gl = (gl_t*)video_driver_get_ptr(NULL);
+ zui_t *zarch = NULL;
+ menu_handle_t *menu = menu_driver_get_ptr();
+ driver_t *driver = driver_get_ptr();
+
+ if (!menu || !menu->userdata || !gl || !driver)
+ return;
+
+ zarch = (zui_t*)menu->userdata;
+
+ menu_display_free_main_font();
+
+ zarch_context_bg_destroy(zarch);
+}
+
+static void zarch_allocate_white_texture(zui_t *zarch)
+{
+ struct texture_image ti;
+ static const uint8_t white_data[] = { 0xff, 0xff, 0xff, 0xff };
+
+ ti.width = 1;
+ ti.height = 1;
+ ti.pixels = (uint32_t*)&white_data;
+
+ zarch->textures.white = video_texture_load(&ti,
+ TEXTURE_BACKEND_OPENGL, TEXTURE_FILTER_NEAREST);
+}
+
+static bool zarch_load_image(void *data, menu_image_type_t type)
+{
+ zui_t *zarch = NULL;
+ menu_handle_t *menu = menu_driver_get_ptr();
+
+ if (!menu || !menu->userdata)
+ return false;
+
+ zarch = (zui_t*)menu->userdata;
+
+ zarch_context_bg_destroy(zarch);
+
+ zarch->textures.bg.id = video_texture_load(data,
+ TEXTURE_BACKEND_OPENGL, TEXTURE_FILTER_MIPMAP_LINEAR);
+ zarch_allocate_white_texture(zarch);
+
+ return true;
+}
+
+static void zarch_context_reset(void)
+{
+ zui_t *zui = NULL;
+ menu_handle_t *menu = menu_driver_get_ptr();
+ settings_t *settings = config_get_ptr();
+ const char *font_path = NULL;
+
+ if (!menu || !menu->userdata || !settings)
+ return;
+
+ zui = (zui_t*)menu->userdata;
+ font_path = settings->video.font_enable ? settings->video.font_path : NULL;
+
+ if (!menu_display_init_main_font(menu, font_path, zui->font_size))
+ RARCH_WARN("Failed to load font.");
+
+ zarch_context_bg_destroy(zui);
+ zarch_allocate_white_texture(zui);
+
+ rarch_main_data_msg_queue_push(DATA_TYPE_IMAGE,
+ settings->menu.wallpaper, "cb_menu_wallpaper", 0, 1, true);
+
+ menu_display_ctl(MENU_DISPLAY_CTL_SET_FONT_SIZE, &zui->font_size);
+ zui_font(menu);
+}
+
+static int zarch_iterate(bool render_this_frame, enum menu_action action)
+{
+ zui_t *zui = NULL;
+ menu_handle_t *menu = menu_driver_get_ptr();
+
+ if (!menu)
+ return 0;
+
+ zui = (zui_t*)menu->userdata;
+
+ if (!zui)
+ return -1;
+
+ if (render_this_frame)
+ {
+ BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
+ BIT64_SET(menu->state, MENU_STATE_BLIT);
+ }
+
+ switch (action)
+ {
+ case MENU_ACTION_UP:
+ zui->load_dlist_first--;
+ break;
+ case MENU_ACTION_DOWN:
+ zui->load_dlist_first++;
+ break;
+ case MENU_ACTION_LEFT:
+ zui->load_dlist_first -= 5;
+ break;
+ case MENU_ACTION_RIGHT:
+ zui->load_dlist_first += 5;
+ break;
+ default:
+ break;
+ }
+
+
+ if (zui->time_to_exit)
+ {
+ RARCH_LOG("Gets here.\n");
+ zui->time_to_exit = false;
+ return -1;
+ }
+
+ return 0;
+}
+
+menu_ctx_driver_t menu_ctx_zarch = {
+ NULL,
+ zarch_get_message,
+ zarch_iterate,
+ zarch_render,
+ zarch_frame,
+ zarch_init,
+ zarch_free,
+ zarch_context_reset,
+ zarch_context_destroy,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ zarch_load_image,
+ "zarch",
+ MENU_VIDEO_DRIVER_OPENGL,
+ NULL,
+};