/* RetroArch - A frontend for libretro. * Copyright (C) 2011-2016 - Daniel De Matteis * Copyright (C) 2014-2015 - Jean-Andr� Santoni * Copyright (C) 2016 - Andr�s Su�rez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- * 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 . */ /* This file is intended for backend code. */ #include #define NK_INCLUDE_FIXED_TYPES #define NK_INCLUDE_STANDARD_IO #define NK_INCLUDE_DEFAULT_ALLOCATOR #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT #define NK_INCLUDE_FONT_BAKING #define NK_INCLUDE_DEFAULT_FONT #define NK_IMPLEMENTATION #include "nk_common.h" #include "../../menu_display.h" #include "../../../gfx/video_shader_driver.h" #include "../../../gfx/drivers/gl_shaders/pipeline_nuklear.glsl.vert.h" #include "../../../gfx/drivers/gl_shaders/pipeline_nuklear.glsl.frag.h" struct nk_font *font; struct nk_font_atlas atlas; struct nk_user_font usrfnt; struct nk_allocator nk_alloc; struct nk_device device; struct nk_image nk_common_image_load(const char *filename) { int x,y,n; GLuint tex; unsigned char *data = stbi_load(filename, &x, &y, &n, 0); if (!data) printf("Failed to load image: %s\n", filename); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) 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); #endif stbi_image_free(data); return nk_image_id((int)tex); } char* nk_common_file_load(const char* path, size_t* size) { void *buf; ssize_t *length = (ssize_t*)size; filestream_read_file(path, &buf, length); return (char*)buf; } void nk_common_device_init(struct nk_device *dev) { #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) GLint status; dev->prog = glCreateProgram(); dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(dev->vert_shdr, 1, &nuklear_vertex_shader, 0); glShaderSource(dev->frag_shdr, 1, &nuklear_fragment_shader, 0); glCompileShader(dev->vert_shdr); glCompileShader(dev->frag_shdr); glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); glAttachShader(dev->prog, dev->vert_shdr); glAttachShader(dev->prog, dev->frag_shdr); glLinkProgram(dev->prog); glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); { /* buffer setup */ GLsizei vs = sizeof(struct nk_draw_vertex); size_t vp = offsetof(struct nk_draw_vertex, position); size_t vt = offsetof(struct nk_draw_vertex, uv); size_t vc = offsetof(struct nk_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); #endif } void device_upload_atlas(struct nk_device *dev, const void *image, int width, int height) { glGenTextures(1, &dev->font_tex); glBindTexture(GL_TEXTURE_2D, dev->font_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); } void nk_common_device_shutdown(struct nk_device *dev) { #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) 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); #endif } void nk_common_device_draw(struct nk_device *dev, struct nk_context *ctx, int width, int height, enum nk_anti_aliasing AA) { video_shader_ctx_info_t shader_info; struct nk_buffer vbuf, ebuf; struct nk_convert_config config; uintptr_t last_prog; const struct nk_draw_command *cmd = NULL; void *vertices = NULL; void *elements = NULL; const nk_draw_index *offset = NULL; #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) GLint 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, (GLint*)&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); #endif menu_display_blend_begin(); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) glActiveTexture(GL_TEXTURE0); #endif /* setup program */ shader_info.data = NULL; shader_info.idx = dev->prog; shader_info.set_active = false; video_shader_driver_use(&shader_info); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); /* convert from command queue into draw list and draw to screen */ /* 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); #endif /* fill converting configuration */ 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 */ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); #endif /* iterate over and execute each draw command */ nk_draw_foreach(cmd, ctx, &dev->cmds) { if (!cmd->elem_count) continue; #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) 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); glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); #endif offset += cmd->elem_count; } nk_clear(ctx); /* restore old state */ shader_info.data = NULL; shader_info.idx = (GLint)last_prog; shader_info.set_active = false; video_shader_driver_use(&shader_info); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) 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); #endif menu_display_blend_end(); } //void nk_mem_alloc(nk_handle a, void *old, nk_size b); void* nk_common_mem_alloc(nk_handle a, void *old, nk_size b) { (void)a; return calloc(1, b); } void nk_common_mem_free(nk_handle unused, void *ptr) { (void)unused; free(ptr); }