805 lines
23 KiB
C
Raw Normal View History

2016-02-14 14:30:28 -05:00
/* RetroArch - A frontend for libretro.
* Copyright (C) 2011-2016 - Daniel De Matteis
* Copyright (C) 2014-2015 - Jean-André Santoni
2016-02-24 16:08:36 -05:00
* Copyright (C) 2016 - Andrés Suárez
2016-02-14 14:30:28 -05:00
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
2016-02-25 21:29:38 +01:00
#include <math.h>
2016-02-14 14:30:28 -05:00
2016-02-25 21:29:38 +01:00
#include <retro_assert.h>
2016-02-14 14:30:28 -05:00
#include <compat/posix_string.h>
#include <file/file_path.h>
#include <formats/image.h>
#include <gfx/math/matrix_4x4.h>
#include <string/stdstring.h>
#include <string/string_list.h>
#include "menu_generic.h"
#include "zr_common.h"
2016-02-14 14:30:28 -05:00
#include "../menu_driver.h"
#include "../menu_animation.h"
#include "../menu_navigation.h"
#include "../menu_hash.h"
#include "../menu_display.h"
#include "../../core_info.h"
#include "../../configuration.h"
#include "../../frontend/frontend_driver.h"
#include "../../system.h"
#include "../../runloop.h"
#include "../../verbosity.h"
#include "../../tasks/tasks_internal.h"
2016-03-05 22:54:56 -05:00
#include "../../deps/stb/stb_image.h"
2016-02-14 14:30:28 -05:00
2016-02-25 21:29:38 +01:00
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
2016-02-14 14:30:28 -05:00
#include "../../gfx/common/gl_common.h"
2016-02-25 21:29:38 +01:00
#endif
2016-02-25 23:16:36 +01:00
#define MAX_VERTEX_MEMORY (512 * 1024)
#define MAX_ELEMENT_MEMORY (128 * 1024)
2016-02-25 21:29:38 +01:00
2016-02-25 21:55:42 +01:00
#define ZR_SYSTEM_TAB_END ZR_SYSTEM_TAB_SETTINGS
struct zr_device
2016-02-25 21:29:38 +01:00
{
struct zr_buffer cmds;
struct zr_draw_null_texture null;
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_proj;
GLuint font_tex;
2016-02-14 14:30:28 -05:00
#endif
2016-02-25 21:29:38 +01:00
};
2016-03-04 19:46:25 +01:00
static struct zr_device device;
static struct zr_font font;
static struct zr_user_font usrfnt;
static struct zr_allocator zr_alloc;
2016-03-05 21:11:03 -05:00
static void zrmenu_main(zrmenu_handle_t *zr)
2016-02-14 14:30:28 -05:00
{
2016-03-05 21:13:14 -05:00
struct zr_context *ctx = &zr->ctx;
2016-02-14 14:30:28 -05:00
2016-03-06 14:13:20 -05:00
if (zr->window[ZRMENU_WND_MAIN].open)
2016-03-05 22:24:01 -05:00
zrmenu_wnd_main(ctx, zr);
2016-03-06 14:13:20 -05:00
if (zr->window[ZRMENU_WND_CONTROL].open)
2016-03-05 21:11:03 -05:00
zrmenu_wnd_control(ctx, zr);
2016-03-06 14:13:20 -05:00
if (zr->window[ZRMENU_WND_SHADER_PARAMETERS].open)
2016-03-05 21:11:03 -05:00
zrmenu_wnd_shader_parameters(ctx, zr);
2016-03-06 14:13:20 -05:00
if (zr->window[ZRMENU_WND_TEST].open)
2016-03-05 21:11:03 -05:00
zrmenu_wnd_test(ctx, zr);
2016-03-06 14:13:20 -05:00
if (zr->window[ZRMENU_WND_WIZARD].open)
2016-03-05 22:24:01 -05:00
zrmenu_wnd_wizard(ctx, zr);
2016-03-06 14:13:20 -05:00
zr->window[ZRMENU_WND_CONTROL].open = !zr_window_is_closed(ctx, "Control");
zr->window[ZRMENU_WND_SHADER_PARAMETERS].open = !zr_window_is_closed(ctx, "Shader Parameters");
zr->window[ZRMENU_WND_TEST].open = !zr_window_is_closed(ctx, "Test");
zr->window[ZRMENU_WND_WIZARD].open = !zr_window_is_closed(ctx, "Setup Wizard");
2016-03-05 22:24:01 -05:00
if(zr_window_is_closed(ctx, "Setup Wizard"))
2016-03-06 14:13:20 -05:00
zr->window[ZRMENU_WND_MAIN].open = true;
2016-03-05 22:24:01 -05:00
2016-03-05 21:13:14 -05:00
zr_buffer_info(&zr->status, &zr->ctx.memory);
2016-02-14 14:30:28 -05:00
}
static char* zrmenu_file_load(const char* path, size_t* size)
2016-02-14 14:30:28 -05:00
{
2016-02-14 15:56:54 -05:00
char *buf;
FILE *fd = fopen(path, "rb");
fseek(fd, 0, SEEK_END);
*size = (size_t)ftell(fd);
2016-02-14 15:56:54 -05:00
fseek(fd, 0, SEEK_SET);
buf = (char*)calloc(*size, 1);
fread(buf, *size, 1, fd);
2016-02-14 15:56:54 -05:00
fclose(fd);
return buf;
2016-02-14 14:30:28 -05:00
}
2016-03-05 22:54:56 -05:00
static struct zr_image zr_icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
2016-03-05 23:09:28 -05:00
if (!data) printf("Failed to load image: %s\n", filename);
2016-03-05 22:54:56 -05:00
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return zr_image_id((int)tex);
}
2016-02-14 14:30:28 -05:00
static void zr_device_init(struct zr_device *dev)
2016-02-14 14:30:28 -05:00
{
2016-02-25 21:29:38 +01:00
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
2016-02-14 15:56:54 -05:00
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
2016-02-25 21:55:42 +01:00
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
2016-02-14 15:56:54 -05:00
{
2016-02-25 21:29:38 +01:00
/* buffer setup */
2016-02-14 15:56:54 -05:00
GLsizei vs = sizeof(struct zr_draw_vertex);
size_t vp = offsetof(struct zr_draw_vertex, position);
size_t vt = offsetof(struct zr_draw_vertex, uv);
size_t vc = offsetof(struct zr_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
2016-02-25 21:29:38 +01:00
#endif
2016-02-14 14:30:28 -05:00
}
2016-02-25 21:55:42 +01:00
static struct zr_user_font font_bake_and_upload(
struct zr_device *dev,
2016-02-25 21:55:42 +01:00
struct zr_font *font,
const char *path,
unsigned int font_height,
const zr_rune *range)
2016-02-14 14:30:28 -05:00
{
2016-02-14 15:56:54 -05:00
int glyph_count;
int img_width, img_height;
struct zr_font_glyph *glyphes;
struct zr_baked_font baked_font;
struct zr_user_font user_font;
struct zr_recti custom;
memset(&baked_font, 0, sizeof(baked_font));
memset(&user_font, 0, sizeof(user_font));
memset(&custom, 0, sizeof(custom));
{
2016-02-25 22:16:25 +01:00
struct texture_image ti;
2016-02-14 15:56:54 -05:00
/* bake and upload font texture */
2016-02-25 21:55:42 +01:00
struct zr_font_config config;
2016-02-14 15:56:54 -05:00
void *img, *tmp;
size_t ttf_size;
size_t tmp_size, img_size;
const char *custom_data = "....";
char *ttf_blob = zrmenu_file_load(path, &ttf_size);
2016-02-14 15:56:54 -05:00
/* setup font configuration */
memset(&config, 0, sizeof(config));
2016-02-25 21:55:42 +01:00
config.ttf_blob = ttf_blob;
config.ttf_size = ttf_size;
config.font = &baked_font;
config.coord_type = ZR_COORD_UV;
config.range = range;
config.pixel_snap = zr_false;
config.size = (float)font_height;
config.spacing = zr_vec2(0,0);
config.oversample_h = 1;
config.oversample_v = 1;
2016-02-14 15:56:54 -05:00
/* query needed amount of memory for the font baking process */
zr_font_bake_memory(&tmp_size, &glyph_count, &config, 1);
2016-02-25 21:55:42 +01:00
glyphes = (struct zr_font_glyph*)
calloc(sizeof(struct zr_font_glyph), (size_t)glyph_count);
2016-02-14 15:56:54 -05:00
tmp = calloc(1, tmp_size);
/* pack all glyphes and return needed image width, height and memory size*/
custom.w = 2; custom.h = 2;
2016-02-25 21:55:42 +01:00
zr_font_bake_pack(&img_size,
&img_width,&img_height,&custom,tmp,tmp_size,&config, 1);
2016-02-14 15:56:54 -05:00
/* bake all glyphes and custom white pixel into image */
img = calloc(1, img_size);
2016-02-25 21:55:42 +01:00
zr_font_bake(img, img_width,
img_height, tmp, tmp_size, glyphes, glyph_count, &config, 1);
zr_font_bake_custom_data(img,
img_width, img_height, custom, custom_data, 2, 2, '.', 'X');
2016-02-14 15:56:54 -05:00
{
/* convert alpha8 image into rgba8 image */
void *img_rgba = calloc(4, (size_t)(img_height * img_width));
zr_font_bake_convert(img_rgba, img_width, img_height, img);
free(img);
img = img_rgba;
}
2016-02-25 21:29:38 +01:00
/* upload baked font image */
2016-02-25 22:11:02 +01:00
ti.pixels = (uint32_t*)img;
2016-02-25 22:04:36 +01:00
ti.width = (GLsizei)img_width;
ti.height = (GLsizei)img_height;
video_driver_texture_load(&ti,
2016-02-27 12:42:16 -05:00
TEXTURE_FILTER_MIPMAP_NEAREST, (uintptr_t*)&dev->font_tex);
2016-02-25 21:29:38 +01:00
2016-02-14 15:56:54 -05:00
free(ttf_blob);
free(tmp);
free(img);
}
/* default white pixel in a texture which is needed to draw primitives */
dev->null.texture.id = (int)dev->font_tex;
dev->null.uv = zr_vec2((custom.x + 0.5f)/(float)img_width,
(custom.y + 0.5f)/(float)img_height);
/* setup font with glyphes. IMPORTANT: the font only references the glyphes
2016-02-14 14:30:28 -05:00
this was done to have the possibility to have multible fonts with one
total glyph array. Not quite sure if it is a good thing since the
glyphes have to be freed as well. */
2016-02-25 21:55:42 +01:00
zr_font_init(font,
(float)font_height, '?', glyphes,
&baked_font, dev->null.texture);
2016-02-14 15:56:54 -05:00
user_font = zr_font_ref(font);
return user_font;
2016-02-14 14:30:28 -05:00
}
static void zr_device_shutdown(struct zr_device *dev)
2016-02-14 14:30:28 -05:00
{
2016-02-25 21:29:38 +01:00
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
2016-02-14 15:56:54 -05:00
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
2016-02-25 21:29:38 +01:00
#endif
2016-02-14 14:30:28 -05:00
}
static void zr_device_draw(struct zr_device *dev,
2016-02-25 21:29:38 +01:00
struct zr_context *ctx, int width, int height,
enum zr_anti_aliasing AA)
2016-02-14 14:30:28 -05:00
{
2016-02-25 21:29:38 +01:00
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
2016-02-14 15:45:19 -05:00
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
2016-02-14 14:30:28 -05:00
2016-02-14 15:45:19 -05:00
{
/* convert from command queue into draw list and draw to screen */
const struct zr_draw_command *cmd;
void *vertices, *elements;
const zr_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
struct zr_buffer vbuf, ebuf;
/* fill converting configuration */
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.line_thickness = 1.0f;
config.null = dev->null;
/* setup buffers to load vertices and elements */
zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
zr_draw_foreach(cmd, ctx, &dev->cmds)
2016-02-14 15:45:19 -05:00
{
if (!cmd->elem_count)
continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
2016-02-25 21:55:42 +01:00
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count,
GL_UNSIGNED_SHORT, offset);
2016-02-14 15:45:19 -05:00
offset += cmd->elem_count;
}
zr_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
2016-02-25 22:54:30 +01:00
glDisable(GL_BLEND);
2016-02-25 21:29:38 +01:00
#endif
2016-02-14 14:30:28 -05:00
}
static void* zrmenu_mem_alloc(zr_handle unused, size_t size)
2016-02-14 15:45:19 -05:00
{
2016-02-25 23:15:28 +01:00
(void)unused;
2016-02-14 15:45:19 -05:00
return calloc(1, size);
}
static void zrmenu_mem_free(zr_handle unused, void *ptr)
2016-02-14 15:45:19 -05:00
{
2016-02-25 23:15:28 +01:00
(void)unused;
2016-02-14 15:45:19 -05:00
free(ptr);
}
2016-02-14 14:30:28 -05:00
static void zrmenu_input_mouse_movement(struct zr_context *ctx)
2016-02-14 20:42:45 -05:00
{
int16_t mouse_x = menu_input_mouse_state(MENU_MOUSE_X_AXIS);
int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS);
2016-02-14 20:42:45 -05:00
zr_input_motion(ctx, mouse_x, mouse_y);
2016-03-05 01:26:45 -05:00
zr_input_scroll(ctx, menu_input_mouse_state(MENU_MOUSE_WHEEL_UP) -
menu_input_mouse_state(MENU_MOUSE_WHEEL_DOWN));
2016-02-14 20:42:45 -05:00
}
static void zrmenu_input_mouse_button(struct zr_context *ctx)
2016-02-14 20:42:45 -05:00
{
int16_t mouse_x = menu_input_mouse_state(MENU_MOUSE_X_AXIS);
int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS);
2016-02-14 21:12:06 -05:00
2016-02-25 21:29:38 +01:00
zr_input_button(ctx, ZR_BUTTON_LEFT,
mouse_x, mouse_y, menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON));
zr_input_button(ctx, ZR_BUTTON_RIGHT,
mouse_x, mouse_y, menu_input_mouse_state(MENU_MOUSE_RIGHT_BUTTON));
2016-02-14 20:42:45 -05:00
}
2016-02-28 23:35:03 -05:00
static void zrmenu_input_keyboard(struct zr_context *ctx)
{
/* placeholder, it just presses 1 on right click
2016-02-28 23:35:03 -05:00
needs to be hooked up correctly
*/
if(menu_input_mouse_state(MENU_MOUSE_RIGHT_BUTTON))
zr_input_char(ctx, '1');
}
static void zrmenu_context_reset_textures(zrmenu_handle_t *zr,
2016-02-14 14:30:28 -05:00
const char *iconpath)
{
unsigned i;
2016-02-25 21:47:32 +01:00
for (i = 0; i < ZR_TEXTURE_LAST; i++)
2016-02-14 14:30:28 -05:00
{
struct texture_image ti = {0};
char path[PATH_MAX_LENGTH] = {0};
switch(i)
{
2016-02-25 21:47:32 +01:00
case ZR_TEXTURE_POINTER:
2016-02-14 14:30:28 -05:00
fill_pathname_join(path, iconpath,
"pointer.png", sizeof(path));
break;
}
if (string_is_empty(path) || !path_file_exists(path))
continue;
video_texture_image_load(&ti, path);
video_driver_texture_load(&ti,
2016-03-05 08:42:35 +01:00
TEXTURE_FILTER_MIPMAP_LINEAR, &zr->textures.list[i]);
2016-02-14 14:30:28 -05:00
video_texture_image_free(&ti);
}
}
2016-03-04 15:08:30 -05:00
static void zrmenu_get_message(void *data, const char *message)
2016-02-14 14:30:28 -05:00
{
zrmenu_handle_t *zr = (zrmenu_handle_t*)data;
2016-02-14 14:30:28 -05:00
if (!zr || !message || !*message)
2016-02-14 14:30:28 -05:00
return;
strlcpy(zr->box_message, message, sizeof(zr->box_message));
2016-02-14 14:30:28 -05:00
}
static void zrmenu_draw_cursor(zrmenu_handle_t *zr,
2016-02-14 14:30:28 -05:00
float *color,
float x, float y, unsigned width, unsigned height)
{
menu_display_ctx_draw_t draw;
struct gfx_coords coords;
coords.vertices = 4;
coords.vertex = NULL;
coords.tex_coord = NULL;
coords.lut_tex_coord = NULL;
coords.color = (const float*)color;
menu_display_ctl(MENU_DISPLAY_CTL_BLEND_BEGIN, NULL);
draw.x = x - 32;
draw.y = (int)height - y - 32;
draw.width = 64;
draw.height = 64;
draw.coords = &coords;
draw.matrix_data = NULL;
2016-03-05 08:42:35 +01:00
draw.texture = zr->textures.list[ZR_TEXTURE_POINTER];
2016-02-14 14:30:28 -05:00
draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP;
menu_display_ctl(MENU_DISPLAY_CTL_DRAW, &draw);
menu_display_ctl(MENU_DISPLAY_CTL_BLEND_END, NULL);
}
static void zrmenu_frame(void *data)
{
2016-02-14 14:30:28 -05:00
float white_bg[16]= {
0.98, 0.98, 0.98, 1,
0.98, 0.98, 0.98, 1,
0.98, 0.98, 0.98, 1,
0.98, 0.98, 0.98, 1,
};
2016-03-02 19:23:34 -05:00
2016-02-14 14:30:28 -05:00
unsigned width, height, ticker_limit, i;
zrmenu_handle_t *zr = (zrmenu_handle_t*)data;
settings_t *settings = config_get_ptr();
2016-02-14 14:30:28 -05:00
if (!zr)
2016-02-14 14:30:28 -05:00
return;
video_driver_get_size(&width, &height);
menu_display_ctl(MENU_DISPLAY_CTL_SET_VIEWPORT, NULL);
2016-02-14 14:30:28 -05:00
2016-03-05 21:13:14 -05:00
zr_input_begin(&zr->ctx);
zrmenu_input_mouse_movement(&zr->ctx);
zrmenu_input_mouse_button(&zr->ctx);
zrmenu_input_keyboard(&zr->ctx);
2016-02-28 23:35:03 -05:00
2016-03-06 14:13:20 -05:00
if (width != zr->size.x || height != zr->size.y)
{
2016-03-06 14:13:20 -05:00
zr->size.x = width;
zr->size.y = height;
zr->size_changed = true;
}
2016-03-05 21:13:14 -05:00
zr_input_end(&zr->ctx);
2016-03-05 21:11:03 -05:00
zrmenu_main(zr);
2016-03-05 21:13:14 -05:00
zr_device_draw(&device, &zr->ctx, width, height, ZR_ANTI_ALIASING_ON);
2016-02-14 21:01:27 -05:00
2016-02-27 14:59:42 -05:00
if (settings->menu.mouse.enable && (settings->video.fullscreen
|| !video_driver_ctl(RARCH_DISPLAY_CTL_HAS_WINDOWED, NULL)))
{
int16_t mouse_x = menu_input_mouse_state(MENU_MOUSE_X_AXIS);
int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS);
zrmenu_draw_cursor(zr, &white_bg[0], mouse_x, mouse_y, width, height);
2016-02-27 14:59:42 -05:00
}
2016-02-14 14:30:28 -05:00
menu_display_ctl(MENU_DISPLAY_CTL_RESTORE_CLEAR_COLOR, NULL);
menu_display_ctl(MENU_DISPLAY_CTL_UNSET_VIEWPORT, NULL);
}
static void zrmenu_layout(zrmenu_handle_t *zr)
2016-02-14 14:30:28 -05:00
{
void *fb_buf;
float scale_factor;
unsigned width, height, new_header_height;
video_driver_get_size(&width, &height);
menu_display_ctl(MENU_DISPLAY_CTL_GET_DPI, &scale_factor);
menu_display_ctl(MENU_DISPLAY_CTL_SET_HEADER_HEIGHT,
&new_header_height);
}
2016-03-05 21:11:03 -05:00
static void zrmenu_init_device(zrmenu_handle_t *zr)
{
2016-03-05 22:54:56 -05:00
char buf[PATH_MAX_LENGTH];
fill_pathname_join(buf, zr->assets_directory,
"DroidSans.ttf", sizeof(buf));
zr_alloc.userdata.ptr = NULL;
zr_alloc.alloc = zrmenu_mem_alloc;
zr_alloc.free = zrmenu_mem_free;
zr_buffer_init(&device.cmds, &zr_alloc, 1024);
2016-03-05 22:54:56 -05:00
usrfnt = font_bake_and_upload(&device, &font, buf, 16,
zr_font_default_glyph_ranges());
2016-03-05 21:13:14 -05:00
zr_init(&zr->ctx, &zr_alloc, &usrfnt);
zr_device_init(&device);
2016-03-05 22:54:56 -05:00
fill_pathname_join(buf, zr->assets_directory, "folder.png", sizeof(buf));
zr->icons.folder = zr_icon_load(buf);
2016-03-05 23:02:29 -05:00
fill_pathname_join(buf, zr->assets_directory, "speaker.png", sizeof(buf));
zr->icons.speaker = zr_icon_load(buf);
2016-03-05 22:54:56 -05:00
2016-03-05 21:13:14 -05:00
zrmenu_set_style(&zr->ctx, THEME_DARK);
zr->size_changed = true;
}
2016-03-04 15:08:30 -05:00
static void *zrmenu_init(void **userdata)
2016-02-14 14:30:28 -05:00
{
2016-02-14 16:17:34 -05:00
settings_t *settings = config_get_ptr();
zrmenu_handle_t *zr = NULL;
2016-02-14 14:30:28 -05:00
menu_handle_t *menu = (menu_handle_t*)
calloc(1, sizeof(*menu));
unsigned width, height = 0;
video_driver_get_size(&width, &height);
2016-02-14 14:30:28 -05:00
if (!menu)
goto error;
if (!menu_display_ctl(MENU_DISPLAY_CTL_INIT_FIRST_DRIVER, NULL))
goto error;
zr = (zrmenu_handle_t*)calloc(1, sizeof(zrmenu_handle_t));
2016-02-14 14:30:28 -05:00
if (!zr)
2016-02-14 14:30:28 -05:00
goto error;
*userdata = zr;
2016-02-14 14:30:28 -05:00
2016-03-05 22:54:56 -05:00
fill_pathname_join(zr->assets_directory, settings->assets_directory,
"zahnrad", sizeof(zr->assets_directory));
2016-03-05 21:11:03 -05:00
zrmenu_init_device(zr);
2016-02-14 14:30:28 -05:00
2016-03-06 14:13:20 -05:00
zr->window[ZRMENU_WND_WIZARD].open = true;
2016-03-05 22:24:01 -05:00
2016-02-14 14:30:28 -05:00
return menu;
error:
if (menu)
free(menu);
return NULL;
}
2016-03-04 15:08:30 -05:00
static void zrmenu_free(void *data)
2016-02-14 14:30:28 -05:00
{
zrmenu_handle_t *zr = (zrmenu_handle_t*)data;
2016-02-14 14:30:28 -05:00
if (!zr)
2016-02-14 14:30:28 -05:00
return;
2016-02-14 16:17:34 -05:00
2016-03-04 15:08:30 -05:00
free(font.glyphs);
2016-03-05 21:13:14 -05:00
zr_free(&zr->ctx);
2016-03-04 15:08:30 -05:00
zr_buffer_free(&device.cmds);
zr_device_shutdown(&device);
2016-02-14 14:30:28 -05:00
gfx_coord_array_free(&zr->list_block.carr);
2016-02-14 14:30:28 -05:00
font_driver_bind_block(NULL, NULL);
}
static void wimp_context_bg_destroy(zrmenu_handle_t *zr)
2016-02-14 14:30:28 -05:00
{
if (!zr)
2016-02-14 14:30:28 -05:00
return;
}
2016-03-03 22:31:22 -05:00
static void zrmenu_context_destroy(void *data)
2016-02-14 14:30:28 -05:00
{
unsigned i;
zrmenu_handle_t *zr = (zrmenu_handle_t*)data;
2016-02-14 14:30:28 -05:00
if (!zr)
2016-02-14 14:30:28 -05:00
return;
2016-02-25 21:47:32 +01:00
for (i = 0; i < ZR_TEXTURE_LAST; i++)
2016-03-05 08:42:35 +01:00
video_driver_texture_unload((uintptr_t*)&zr->textures.list[i]);
2016-02-14 14:30:28 -05:00
menu_display_ctl(MENU_DISPLAY_CTL_FONT_MAIN_DEINIT, NULL);
wimp_context_bg_destroy(zr);
2016-02-14 14:30:28 -05:00
}
2016-03-03 22:31:22 -05:00
static void zrmenu_context_reset(void *data)
2016-02-14 14:30:28 -05:00
{
char iconpath[PATH_MAX_LENGTH] = {0};
zrmenu_handle_t *zr = (zrmenu_handle_t*)data;
2016-02-14 14:30:28 -05:00
settings_t *settings = config_get_ptr();
unsigned width, height = 0;
video_driver_get_size(&width, &height);
2016-02-14 14:30:28 -05:00
if (!zr || !settings)
2016-02-14 14:30:28 -05:00
return;
fill_pathname_join(iconpath, settings->assets_directory,
2016-02-27 15:02:13 -05:00
"zahnrad", sizeof(iconpath));
2016-02-14 14:30:28 -05:00
fill_pathname_slash(iconpath, sizeof(iconpath));
zrmenu_layout(zr);
2016-03-05 21:11:03 -05:00
zrmenu_init_device(zr);
wimp_context_bg_destroy(zr);
zrmenu_context_reset_textures(zr, iconpath);
2016-02-14 14:30:28 -05:00
rarch_task_push_image_load(settings->menu.wallpaper, "cb_menu_wallpaper",
menu_display_handle_wallpaper_upload, NULL);
}
2016-03-05 21:59:01 -05:00
static int zrmenu_environ(enum menu_environ_cb type, void *data, void *userdata)
2016-02-14 14:30:28 -05:00
{
switch (type)
{
case 0:
default:
break;
}
return -1;
}
2016-03-03 22:31:22 -05:00
static bool zrmenu_init_list(void *data)
2016-03-02 22:40:38 -05:00
{
menu_displaylist_info_t info = {0};
file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0);
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
strlcpy(info.label,
menu_hash_to_str(MENU_VALUE_HISTORY_TAB), sizeof(info.label));
menu_entries_push(menu_stack,
info.path, info.label, info.type, info.flags, 0);
event_cmd_ctl(EVENT_CMD_HISTORY_INIT, NULL);
info.list = selection_buf;
if (menu_displaylist_ctl(DISPLAYLIST_HISTORY, &info))
{
info.need_push = true;
return menu_displaylist_ctl(DISPLAYLIST_PROCESS, &info);
}
return false;
}
2016-02-25 21:29:38 +01:00
menu_ctx_driver_t menu_ctx_zr = {
2016-02-14 14:30:28 -05:00
NULL,
2016-03-04 15:08:30 -05:00
zrmenu_get_message,
2016-02-14 14:30:28 -05:00
generic_menu_iterate,
2016-03-03 22:31:22 -05:00
NULL,
zrmenu_frame,
2016-03-04 15:08:30 -05:00
zrmenu_init,
zrmenu_free,
2016-03-03 22:31:22 -05:00
zrmenu_context_reset,
zrmenu_context_destroy,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
zrmenu_init_list,
NULL,
NULL,
NULL,
2016-02-14 14:30:28 -05:00
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
2016-02-26 12:21:42 +01:00
"zahnrad",
2016-03-05 21:59:01 -05:00
zrmenu_environ,
2016-02-26 15:57:22 +01:00
NULL,
2016-02-14 14:30:28 -05:00
};