Last active
April 25, 2016 14:05
-
-
Save daumiller/9301246b24b3efe5b26006d88856747f to your computer and use it in GitHub Desktop.
Nuklear GLFW with older OpenGL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#define MAX_VERTEX_BUFFER 512 * 1024 | |
#define MAX_ELEMENT_BUFFER 128 * 1024 | |
#define NK_IMPLEMENTATION | |
#include "nuklear_glfw.h" | |
#include "../../nuklear.h" | |
#define NK_GLFW_TEXT_MAX 256 | |
struct nk_glfw_device { | |
struct nk_buffer cmds; | |
struct nk_draw_null_texture null; | |
GLuint font_tex; | |
struct nk_draw_vertex *vertices; | |
nk_draw_index *elements; | |
}; | |
static struct nk_glfw { | |
GLFWwindow *win; | |
struct nk_glfw_device ogl; | |
struct nk_context ctx; | |
struct nk_font_atlas atlas; | |
unsigned int text[NK_GLFW_TEXT_MAX]; | |
int text_len; | |
float scroll; | |
} glfw; | |
NK_API void | |
nk_glfw3_device_create(void) | |
{ | |
GLint status; | |
struct nk_glfw_device *dev = &glfw.ogl; | |
nk_buffer_init_default(&dev->cmds); | |
dev->vertices = malloc(MAX_VERTEX_BUFFER); | |
dev->elements = malloc(MAX_ELEMENT_BUFFER); | |
glBindTexture(GL_TEXTURE_2D, 0); | |
} | |
NK_INTERN void | |
nk_glfw3_device_upload_atlas(const void *image, int width, int height) | |
{ | |
struct nk_glfw_device *dev = &glfw.ogl; | |
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); | |
} | |
NK_API void | |
nk_glfw3_device_destroy(void) | |
{ | |
struct nk_glfw_device *dev = &glfw.ogl; | |
glDeleteTextures(1, &dev->font_tex); | |
free(dev->vertices); | |
free(dev->elements); | |
nk_buffer_free(&dev->cmds); | |
} | |
NK_API void | |
nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) | |
{ | |
struct nk_glfw_device *dev = &glfw.ogl; | |
int width, height, pixelWidth, pixelHeight; | |
double scaleX, scaleY; | |
glfwGetWindowSize(glfw.win, &width, &height); | |
/* scaling fix for Retina/High-DPI displays */ | |
glfwGetFramebufferSize(glfw.win, &pixelWidth, &pixelHeight); | |
scaleX = (double)pixelWidth / (double)width; | |
scaleY = (double)pixelHeight / (double)height; | |
/* setup global state */ | |
glEnable(GL_BLEND); | |
glBlendEquation(GL_FUNC_ADD); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
glDisable(GL_CULL_FACE); | |
glDisable(GL_DEPTH_TEST); | |
glEnable(GL_SCISSOR_TEST); | |
glEnable(GL_TEXTURE_2D); | |
glEnableClientState(GL_VERTEX_ARRAY); | |
glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
glEnableClientState(GL_COLOR_ARRAY); | |
/* setup program */ | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glOrtho(0.0, (GLfloat)width, (GLfloat)height, 0.0, -1.0, +1.0); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
{ | |
/* convert from command queue into draw list and draw to screen */ | |
const struct nk_draw_command *cmd; | |
const nk_draw_index *elemIndex = dev->elements; | |
const unsigned char *ptrVert = (const unsigned char *)dev->vertices; | |
GLvoid *ptrVertPos = (GLvoid *)(ptrVert + offsetof(struct nk_draw_vertex, position)); | |
GLvoid *ptrVertTex = (GLvoid *)(ptrVert + offsetof(struct nk_draw_vertex, uv)); | |
GLvoid *ptrVertCol = (GLvoid *)(ptrVert + offsetof(struct nk_draw_vertex, col)); | |
{ | |
/* fill converting configuration */ | |
struct nk_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.curve_segment_count = 22; | |
config.arc_segment_count = 22; | |
config.null = dev->null; | |
/* setup buffers to load vertices and elements */ | |
{struct nk_buffer vbuf, ebuf; | |
nk_buffer_init_fixed(&vbuf, dev->vertices, (size_t)max_vertex_buffer); | |
nk_buffer_init_fixed(&ebuf, dev->elements, (size_t)max_element_buffer); | |
nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);} | |
} | |
glVertexPointer (2, GL_FLOAT, sizeof(struct nk_draw_vertex), ptrVertPos); | |
glTexCoordPointer(2, GL_FLOAT, sizeof(struct nk_draw_vertex), ptrVertTex); | |
glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(struct nk_draw_vertex), ptrVertCol); | |
/* iterate over and execute each draw command */ | |
nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) { | |
if (!cmd->elem_count) continue; | |
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); | |
glScissor((GLint)((double)cmd->clip_rect.x * scaleX), | |
(GLint)((double)(height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scaleY), | |
(GLint)((double)cmd->clip_rect.w * scaleX), (GLint)((double)cmd->clip_rect.h * scaleY)); | |
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, elemIndex); | |
elemIndex += cmd->elem_count; | |
} | |
nk_clear(&glfw.ctx); | |
} | |
/* restore old state */ | |
glDisable(GL_SCISSOR_TEST); | |
glDisableClientState(GL_VERTEX_ARRAY); | |
glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
glDisableClientState(GL_COLOR_ARRAY); | |
glDisable(GL_TEXTURE_2D); | |
} | |
NK_API void | |
nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) | |
{ | |
(void)win; | |
if (glfw.text_len < NK_GLFW_TEXT_MAX) | |
glfw.text[glfw.text_len++] = codepoint; | |
} | |
NK_API void | |
nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) | |
{ | |
(void)win; (void)xoff; | |
glfw.scroll += (float)yoff; | |
} | |
static void | |
nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) | |
{ | |
const char *text = glfwGetClipboardString(glfw.win); | |
if (text) nk_textedit_paste(edit, text, nk_strlen(text)); | |
(void)usr; | |
} | |
static void | |
nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) | |
{ | |
char *str = 0; | |
(void)usr; | |
if (!len) return; | |
str = malloc((size_t)len+1); | |
if (!str) return; | |
memcpy(str, text, (size_t)len); | |
str[len] = '\0'; | |
glfwSetClipboardString(glfw.win, str); | |
free(str); | |
} | |
NK_API struct nk_context* | |
nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) | |
{ | |
glfw.win = win; | |
if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { | |
glfwSetScrollCallback(win, nk_gflw3_scroll_callback); | |
glfwSetCharCallback(win, nk_glfw3_char_callback); | |
} | |
nk_init_default(&glfw.ctx, 0); | |
glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; | |
glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; | |
glfw.ctx.clip.userdata = nk_handle_ptr(0); | |
nk_glfw3_device_create(); | |
return &glfw.ctx; | |
} | |
NK_API void | |
nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) | |
{ | |
nk_font_atlas_init_default(&glfw.atlas); | |
nk_font_atlas_begin(&glfw.atlas); | |
*atlas = &glfw.atlas; | |
} | |
NK_API void | |
nk_glfw3_font_stash_end(void) | |
{ | |
const void *image; int w, h; | |
image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); | |
nk_glfw3_device_upload_atlas(image, w, h); | |
nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); | |
if (glfw.atlas.default_font) | |
nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); | |
} | |
NK_API void | |
nk_glfw3_new_frame(void) | |
{ | |
int i; | |
double x, y; | |
struct nk_context *ctx = &glfw.ctx; | |
struct GLFWwindow *win = glfw.win; | |
nk_input_begin(ctx); | |
for (i = 0; i < glfw.text_len; ++i) | |
nk_input_unicode(ctx, glfw.text[i]); | |
nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| | |
glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); | |
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || | |
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) { | |
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); | |
} else { | |
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |
nk_input_key(ctx, NK_KEY_COPY, 0); | |
nk_input_key(ctx, NK_KEY_PASTE, 0); | |
nk_input_key(ctx, NK_KEY_CUT, 0); | |
nk_input_key(ctx, NK_KEY_SHIFT, 0); | |
} | |
glfwGetCursorPos(win, &x, &y); | |
nk_input_motion(ctx, (int)x, (int)y); | |
nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); | |
nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); | |
nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); | |
nk_input_scroll(ctx, glfw.scroll); | |
nk_input_end(&glfw.ctx); | |
glfw.text_len = 0; | |
glfw.scroll = 0; | |
} | |
NK_API | |
void nk_glfw3_shutdown(void) | |
{ | |
nk_font_atlas_clear(&glfw.atlas); | |
nk_free(&glfw.ctx); | |
nk_glfw3_device_destroy(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment