b3b0c9ee02
## Forward compatibility (GLFW_OPENGL_FORWARD_COMPAT) Fix for error 65543 on macOS: Error `65543`: NSGL: The targeted version of OS X only supports forward-compatible contexts for OpenGL 3.2 and above Quote from docs: GLFW_OPENGL_FORWARD_COMPAT specifies whether the OpenGL context should be forward-compatible, i.e. one where all functionality deprecated in the requested version of OpenGL is removed. This must only be used if the requested OpenGL version is 3.0 or above.
491 lines
18 KiB
C
491 lines
18 KiB
C
/* nuklear - v1.05 - public domain */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <limits.h>
|
|
|
|
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#define NK_PRIVATE
|
|
#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 "../nuklear.h"
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "stb_image.h"
|
|
|
|
/* macros */
|
|
#define WINDOW_WIDTH 1200
|
|
#define WINDOW_HEIGHT 800
|
|
|
|
#define MAX_VERTEX_MEMORY 512 * 1024
|
|
#define MAX_ELEMENT_MEMORY 128 * 1024
|
|
|
|
#define UNUSED(a) (void)a
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
|
#define LEN(a) (sizeof(a)/sizeof(a)[0])
|
|
|
|
#define NK_SHADER_VERSION "#version 150\n"
|
|
|
|
/* ===============================================================
|
|
*
|
|
* DEVICE
|
|
*
|
|
* ===============================================================*/
|
|
struct nk_glfw_vertex {
|
|
float position[2];
|
|
float uv[2];
|
|
nk_byte col[4];
|
|
};
|
|
|
|
struct device {
|
|
struct nk_buffer cmds;
|
|
struct nk_draw_null_texture null;
|
|
GLuint vbo, vao, ebo;
|
|
GLuint prog;
|
|
GLuint vert_shdr;
|
|
GLuint frag_shdr;
|
|
GLint attrib_pos;
|
|
GLint attrib_uv;
|
|
GLint attrib_col;
|
|
GLint uniform_tex;
|
|
GLint uniform_proj;
|
|
GLuint font_tex;
|
|
};
|
|
|
|
static void
|
|
die(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
fputs("\n", stderr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static struct nk_image
|
|
icon_load(const char *filename)
|
|
{
|
|
int x,y,n;
|
|
GLuint tex;
|
|
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
|
|
if (!data) die("[SDL]: failed to load image: %s", filename);
|
|
|
|
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 nk_image_id((int)tex);
|
|
}
|
|
|
|
static void
|
|
device_init(struct device *dev)
|
|
{
|
|
GLint status;
|
|
static const GLchar *vertex_shader =
|
|
NK_SHADER_VERSION
|
|
"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 =
|
|
NK_SHADER_VERSION
|
|
"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";
|
|
|
|
nk_buffer_init_default(&dev->cmds);
|
|
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_tex = glGetUniformLocation(dev->prog, "Texture");
|
|
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_glfw_vertex);
|
|
size_t vp = offsetof(struct nk_glfw_vertex, position);
|
|
size_t vt = offsetof(struct nk_glfw_vertex, uv);
|
|
size_t vc = offsetof(struct nk_glfw_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);
|
|
}
|
|
|
|
static void
|
|
device_upload_atlas(struct 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);
|
|
}
|
|
|
|
static void
|
|
device_shutdown(struct device *dev)
|
|
{
|
|
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);
|
|
nk_buffer_free(&dev->cmds);
|
|
}
|
|
|
|
static void
|
|
device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
|
|
enum nk_anti_aliasing AA)
|
|
{
|
|
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;
|
|
|
|
/* 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);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
/* setup program */
|
|
glUseProgram(dev->prog);
|
|
glUniform1i(dev->uniform_tex, 0);
|
|
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
|
|
{
|
|
/* convert from command queue into draw list and draw to screen */
|
|
const struct nk_draw_command *cmd;
|
|
void *vertices, *elements;
|
|
const nk_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);
|
|
{
|
|
/* fill convert configuration */
|
|
struct nk_convert_config config;
|
|
static const struct nk_draw_vertex_layout_element vertex_layout[] = {
|
|
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
|
|
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
|
|
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
|
|
{NK_VERTEX_LAYOUT_END}
|
|
};
|
|
NK_MEMSET(&config, 0, sizeof(config));
|
|
config.vertex_layout = vertex_layout;
|
|
config.vertex_size = sizeof(struct nk_glfw_vertex);
|
|
config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
|
|
config.null = dev->null;
|
|
config.circle_segment_count = 22;
|
|
config.curve_segment_count = 22;
|
|
config.arc_segment_count = 22;
|
|
config.global_alpha = 1.0f;
|
|
config.shape_AA = AA;
|
|
config.line_AA = AA;
|
|
|
|
/* setup buffers to load vertices and elements */
|
|
{struct nk_buffer vbuf, ebuf;
|
|
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);}
|
|
}
|
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
|
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
|
|
|
/* iterate over and execute each draw command */
|
|
nk_draw_foreach(cmd, ctx, &dev->cmds)
|
|
{
|
|
if (!cmd->elem_count) continue;
|
|
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
|
|
glScissor(
|
|
(GLint)(cmd->clip_rect.x),
|
|
(GLint)((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);
|
|
offset += cmd->elem_count;
|
|
}
|
|
nk_clear(ctx);
|
|
}
|
|
|
|
/* default OpenGL state */
|
|
glUseProgram(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
|
|
static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
|
|
static void text_input(GLFWwindow *win, unsigned int codepoint)
|
|
{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
|
|
static void scroll_input(GLFWwindow *win, double _, double yoff)
|
|
{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}
|
|
|
|
static void
|
|
pump_input(struct nk_context *ctx, GLFWwindow *win)
|
|
{
|
|
double x, y;
|
|
nk_input_begin(ctx);
|
|
glfwPollEvents();
|
|
|
|
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_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_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
|
|
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
|
|
|
|
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
|
|
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
|
|
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_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
|
|
nk_input_key(ctx, NK_KEY_SHIFT, 1);
|
|
} else {
|
|
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_end(ctx);
|
|
}
|
|
|
|
struct nk_canvas {
|
|
struct nk_command_buffer *painter;
|
|
struct nk_vec2 item_spacing;
|
|
struct nk_vec2 panel_padding;
|
|
struct nk_style_item window_background;
|
|
};
|
|
|
|
static void
|
|
canvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags,
|
|
int x, int y, int width, int height, struct nk_color background_color)
|
|
{
|
|
/* save style properties which will be overwritten */
|
|
canvas->panel_padding = ctx->style.window.padding;
|
|
canvas->item_spacing = ctx->style.window.spacing;
|
|
canvas->window_background = ctx->style.window.fixed_background;
|
|
|
|
/* use the complete window space and set background */
|
|
ctx->style.window.spacing = nk_vec2(0,0);
|
|
ctx->style.window.padding = nk_vec2(0,0);
|
|
ctx->style.window.fixed_background = nk_style_item_color(background_color);
|
|
|
|
/* create/update window and set position + size */
|
|
flags = flags & ~NK_WINDOW_DYNAMIC;
|
|
nk_window_set_bounds(ctx, "Window", nk_rect(x, y, width, height));
|
|
nk_begin(ctx, "Window", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags);
|
|
|
|
/* allocate the complete window space for drawing */
|
|
{struct nk_rect total_space;
|
|
total_space = nk_window_get_content_region(ctx);
|
|
nk_layout_row_dynamic(ctx, total_space.h, 1);
|
|
nk_widget(&total_space, ctx);
|
|
canvas->painter = nk_window_get_canvas(ctx);}
|
|
}
|
|
|
|
static void
|
|
canvas_end(struct nk_context *ctx, struct nk_canvas *canvas)
|
|
{
|
|
nk_end(ctx);
|
|
ctx->style.window.spacing = canvas->panel_padding;
|
|
ctx->style.window.padding = canvas->item_spacing;
|
|
ctx->style.window.fixed_background = canvas->window_background;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
/* Platform */
|
|
static GLFWwindow *win;
|
|
int width = 0, height = 0;
|
|
|
|
/* GUI */
|
|
struct device device;
|
|
struct nk_font_atlas atlas;
|
|
struct nk_context ctx;
|
|
|
|
/* GLFW */
|
|
glfwSetErrorCallback(error_callback);
|
|
if (!glfwInit()) {
|
|
fprintf(stdout, "[GFLW] failed to init!\n");
|
|
exit(1);
|
|
}
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
|
|
glfwMakeContextCurrent(win);
|
|
glfwSetWindowUserPointer(win, &ctx);
|
|
glfwSetCharCallback(win, text_input);
|
|
glfwSetScrollCallback(win, scroll_input);
|
|
glfwGetWindowSize(win, &width, &height);
|
|
|
|
/* OpenGL */
|
|
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
|
glewExperimental = 1;
|
|
if (glewInit() != GLEW_OK) {
|
|
fprintf(stderr, "Failed to setup GLEW\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* GUI */
|
|
{device_init(&device);
|
|
{const void *image; int w, h;
|
|
struct nk_font *font;
|
|
nk_font_atlas_init_default(&atlas);
|
|
nk_font_atlas_begin(&atlas);
|
|
font = nk_font_atlas_add_default(&atlas, 13, 0);
|
|
image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
|
|
device_upload_atlas(&device, image, w, h);
|
|
nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);
|
|
nk_init_default(&ctx, &font->handle);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
while (!glfwWindowShouldClose(win))
|
|
{
|
|
/* input */
|
|
pump_input(&ctx, win);
|
|
|
|
/* draw */
|
|
{struct nk_canvas canvas;
|
|
canvas_begin(&ctx, &canvas, 0, 0, 0, width, height, nk_rgb(250,250,250));
|
|
{
|
|
nk_fill_rect(canvas.painter, nk_rect(15,15,210,210), 5, nk_rgb(247, 230, 154));
|
|
nk_fill_rect(canvas.painter, nk_rect(20,20,200,200), 5, nk_rgb(188, 174, 118));
|
|
nk_draw_text(canvas.painter, nk_rect(30, 30, 150, 20), "Text to draw", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0));
|
|
nk_fill_rect(canvas.painter, nk_rect(250,20,100,100), 0, nk_rgb(0,0,255));
|
|
nk_fill_circle(canvas.painter, nk_rect(20,250,100,100), nk_rgb(255,0,0));
|
|
nk_fill_triangle(canvas.painter, 250, 250, 350, 250, 300, 350, nk_rgb(0,255,0));
|
|
nk_fill_arc(canvas.painter, 300, 180, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0));
|
|
|
|
{float points[12];
|
|
points[0] = 200; points[1] = 250;
|
|
points[2] = 250; points[3] = 350;
|
|
points[4] = 225; points[5] = 350;
|
|
points[6] = 200; points[7] = 300;
|
|
points[8] = 175; points[9] = 350;
|
|
points[10] = 150; points[11] = 350;
|
|
nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));}
|
|
|
|
nk_stroke_line(canvas.painter, 15, 10, 200, 10, 2.0f, nk_rgb(189,45,75));
|
|
nk_stroke_rect(canvas.painter, nk_rect(370, 20, 100, 100), 10, 3, nk_rgb(0,0,255));
|
|
nk_stroke_curve(canvas.painter, 380, 200, 405, 270, 455, 120, 480, 200, 2, nk_rgb(0,150,220));
|
|
nk_stroke_circle(canvas.painter, nk_rect(20, 370, 100, 100), 5, nk_rgb(0,255,120));
|
|
nk_stroke_triangle(canvas.painter, 370, 250, 470, 250, 420, 350, 6, nk_rgb(255,0,143));
|
|
}
|
|
canvas_end(&ctx, &canvas);}
|
|
|
|
/* Draw */
|
|
glfwGetWindowSize(win, &width, &height);
|
|
glViewport(0, 0, width, height);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
|
|
device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
|
|
glfwSwapBuffers(win);
|
|
}}}
|
|
nk_font_atlas_clear(&atlas);
|
|
nk_free(&ctx);
|
|
device_shutdown(&device);
|
|
glfwTerminate();
|
|
return 0;
|
|
}
|
|
|