1 /*
2  * Nuklear - v1.17 - public domain
3  * no warrenty implied; use at your own risk.
4  * authored from 2015-2016 by Micha Mettke
5  */
6 /*
7  * ==============================================================
8  *
9  *                              API
10  *
11  * ===============================================================
12  */
13 #ifndef NK_XLIB_GL3_H_
14 #define NK_XLIB_GL3_H_
15 
16 #include <X11/Xlib.h>
17 NK_API struct nk_context*   nk_x11_init(Display *dpy, Window win);
18 NK_API void                 nk_x11_font_stash_begin(struct nk_font_atlas **atlas);
19 NK_API void                 nk_x11_font_stash_end(void);
20 NK_API int                  nk_x11_handle_event(XEvent *evt);
21 NK_API void                 nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
22 NK_API void                 nk_x11_shutdown(void);
23 NK_API int                  nk_x11_device_create(void);
24 NK_API void                 nk_x11_device_destroy(void);
25 
26 #endif
27 /*
28  * ==============================================================
29  *
30  *                          IMPLEMENTATION
31  *
32  * ===============================================================
33  */
34 #ifdef NK_XLIB_GL3_IMPLEMENTATION
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <sys/time.h>
40 #include <unistd.h>
41 #include <time.h>
42 
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xresource.h>
46 #include <X11/Xlocale.h>
47 
48 #include <GL/gl.h>
49 #include <GL/glx.h>
50 
51 #ifndef NK_X11_DOUBLE_CLICK_LO
52 #define NK_X11_DOUBLE_CLICK_LO 20
53 #endif
54 #ifndef NK_X11_DOUBLE_CLICK_HI
55 #define NK_X11_DOUBLE_CLICK_HI 200
56 #endif
57 
58 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
59 #include <GL/glxext.h>
60 
61 /* GL_ARB_vertex_buffer_object */
62 typedef void(*nkglGenBuffers)(GLsizei, GLuint*);
63 typedef void(*nkglBindBuffer)(GLenum, GLuint);
64 typedef void(*nkglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
65 typedef void(*nkglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);
66 typedef void*(*nkglMapBuffer)(GLenum, GLenum);
67 typedef GLboolean(*nkglUnmapBuffer)(GLenum);
68 typedef void(*nkglDeleteBuffers)(GLsizei, GLuint*);
69 /* GL_ARB_vertex_array_object */
70 typedef void (*nkglGenVertexArrays)(GLsizei, GLuint*);
71 typedef void (*nkglBindVertexArray)(GLuint);
72 typedef void (*nkglDeleteVertexArrays)(GLsizei, const GLuint*);
73 /* GL_ARB_vertex_program / GL_ARB_fragment_program */
74 typedef void(*nkglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
75 typedef void(*nkglEnableVertexAttribArray)(GLuint);
76 typedef void(*nkglDisableVertexAttribArray)(GLuint);
77 /* GL_ARB_framebuffer_object */
78 typedef void(*nkglGenerateMipmap)(GLenum target);
79 /* GLSL/OpenGL 2.0 core */
80 typedef GLuint(*nkglCreateShader)(GLenum);
81 typedef void(*nkglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);
82 typedef void(*nkglCompileShader)(GLuint);
83 typedef void(*nkglGetShaderiv)(GLuint, GLenum, GLint*);
84 typedef void(*nkglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
85 typedef void(*nkglDeleteShader)(GLuint);
86 typedef GLuint(*nkglCreateProgram)(void);
87 typedef void(*nkglAttachShader)(GLuint, GLuint);
88 typedef void(*nkglDetachShader)(GLuint, GLuint);
89 typedef void(*nkglLinkProgram)(GLuint);
90 typedef void(*nkglUseProgram)(GLuint);
91 typedef void(*nkglGetProgramiv)(GLuint, GLenum, GLint*);
92 typedef void(*nkglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
93 typedef void(*nkglDeleteProgram)(GLuint);
94 typedef GLint(*nkglGetUniformLocation)(GLuint, const GLchar*);
95 typedef GLint(*nkglGetAttribLocation)(GLuint, const GLchar*);
96 typedef void(*nkglUniform1i)(GLint, GLint);
97 typedef void(*nkglUniform1f)(GLint, GLfloat);
98 typedef void(*nkglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);
99 typedef void(*nkglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);
100 
101 static nkglGenBuffers glGenBuffers;
102 static nkglBindBuffer glBindBuffer;
103 static nkglBufferData glBufferData;
104 static nkglBufferSubData glBufferSubData;
105 static nkglMapBuffer glMapBuffer;
106 static nkglUnmapBuffer glUnmapBuffer;
107 static nkglDeleteBuffers glDeleteBuffers;
108 static nkglGenVertexArrays glGenVertexArrays;
109 static nkglBindVertexArray glBindVertexArray;
110 static nkglDeleteVertexArrays glDeleteVertexArrays;
111 static nkglVertexAttribPointer glVertexAttribPointer;
112 static nkglEnableVertexAttribArray glEnableVertexAttribArray;
113 static nkglDisableVertexAttribArray glDisableVertexAttribArray;
114 static nkglGenerateMipmap glGenerateMipmap;
115 static nkglCreateShader glCreateShader;
116 static nkglShaderSource glShaderSource;
117 static nkglCompileShader glCompileShader;
118 static nkglGetShaderiv glGetShaderiv;
119 static nkglGetShaderInfoLog glGetShaderInfoLog;
120 static nkglDeleteShader glDeleteShader;
121 static nkglCreateProgram glCreateProgram;
122 static nkglAttachShader glAttachShader;
123 static nkglDetachShader glDetachShader;
124 static nkglLinkProgram glLinkProgram;
125 static nkglUseProgram glUseProgram;
126 static nkglGetProgramiv glGetProgramiv;
127 static nkglGetProgramInfoLog glGetProgramInfoLog;
128 static nkglDeleteProgram glDeleteProgram;
129 static nkglGetUniformLocation glGetUniformLocation;
130 static nkglGetAttribLocation glGetAttribLocation;
131 static nkglUniform1i glUniform1i;
132 static nkglUniform1f glUniform1f;
133 static nkglUniformMatrix3fv glUniformMatrix3fv;
134 static nkglUniformMatrix4fv glUniformMatrix4fv;
135 
136 enum graphics_card_vendors {
137     VENDOR_UNKNOWN,
138     VENDOR_NVIDIA,
139     VENDOR_AMD,
140     VENDOR_INTEL
141 };
142 
143 struct opengl_info {
144     /* info */
145     const char *vendor_str;
146     const char *version_str;
147     const char *extensions_str;
148     const char *renderer_str;
149     const char *glsl_version_str;
150     enum graphics_card_vendors vendor;
151     /* version */
152     float version;
153     int major_version;
154     int minor_version;
155     /* extensions */
156     int glsl_available;
157     int vertex_buffer_obj_available;
158     int vertex_array_obj_available;
159     int map_buffer_range_available;
160     int fragment_program_available;
161     int frame_buffer_object_available;
162 };
163 #endif
164 
165 struct nk_x11_vertex {
166     float position[2];
167     float uv[2];
168     nk_byte col[4];
169 };
170 
171 struct nk_x11_device {
172 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
173     struct opengl_info info;
174 #endif
175     struct nk_buffer cmds;
176     struct nk_draw_null_texture null;
177     GLuint vbo, vao, ebo;
178     GLuint prog;
179     GLuint vert_shdr;
180     GLuint frag_shdr;
181     GLint attrib_pos;
182     GLint attrib_uv;
183     GLint attrib_col;
184     GLint uniform_tex;
185     GLint uniform_proj;
186     GLuint font_tex;
187 };
188 
189 static struct nk_x11 {
190     struct nk_x11_device ogl;
191     struct nk_context ctx;
192     struct nk_font_atlas atlas;
193     Cursor cursor;
194     Display *dpy;
195     Window win;
196     long last_button_click;
197 } x11;
198 
199 #ifdef __APPLE__
200   #define NK_SHADER_VERSION "#version 150\n"
201 #else
202   #define NK_SHADER_VERSION "#version 300 es\n"
203 #endif
204 
205 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
206 #include <GL/glx.h>
207 
208 NK_INTERN long
nk_timestamp(void)209 nk_timestamp(void)
210 {
211     struct timeval tv;
212     if (gettimeofday(&tv, NULL) < 0) return 0;
213     return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
214 }
215 
216 NK_INTERN int
nk_x11_stricmpn(const char * a,const char * b,int len)217 nk_x11_stricmpn(const char *a, const char *b, int len)
218 {
219     int i = 0;
220     for (i = 0; i < len && a[i] && b[i]; ++i)
221         if (a[i] != b[i]) return 1;
222     if (i != len) return 1;
223     return 0;
224 }
225 
226 NK_INTERN int
nk_x11_check_extension(struct opengl_info * GL,const char * ext)227 nk_x11_check_extension(struct opengl_info *GL, const char *ext)
228 {
229     const char *start, *where, *term;
230     where = strchr(ext, ' ');
231     if (where || *ext == '\0')
232         return nk_false;
233 
234     for (start = GL->extensions_str;;) {
235         where = strstr((const char*)start, ext);
236         if (!where) break;
237         term = where + strlen(ext);
238         if (where == start || *(where - 1) == ' ') {
239             if (*term == ' ' || *term == '\0')
240                 return nk_true;
241         }
242         start = term;
243     }
244     return nk_false;
245 }
246 
247 #define GL_EXT(name) (nk##name)nk_gl_ext(#name)
248 NK_INTERN __GLXextFuncPtr
nk_gl_ext(const char * name)249 nk_gl_ext(const char *name)
250 {
251     __GLXextFuncPtr func;
252     func = glXGetProcAddress((const GLubyte*)name);
253     if (!func) {
254         fprintf(stdout, "[GL]: failed to load extension: %s", name);
255         return NULL;
256     }
257     return func;
258 }
259 
260 NK_INTERN int
nk_load_opengl(struct opengl_info * gl)261 nk_load_opengl(struct opengl_info *gl)
262 {
263     int failed = nk_false;
264     gl->version_str = (const char*)glGetString(GL_VERSION);
265     glGetIntegerv(GL_MAJOR_VERSION, &gl->major_version);
266     glGetIntegerv(GL_MINOR_VERSION, &gl->minor_version);
267     if (gl->major_version < 2) {
268         fprintf(stderr, "[GL]: Graphics card does not fulfill minimum OpenGL 2.0 support\n");
269         return 0;
270     }
271     gl->version = (float)gl->major_version + (float)gl->minor_version * 0.1f;
272     gl->renderer_str = (const char*)glGetString(GL_RENDERER);
273     gl->extensions_str = (const char*)glGetString(GL_EXTENSIONS);
274     gl->glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
275     gl->vendor_str = (const char*)glGetString(GL_VENDOR);
276     if (!nk_x11_stricmpn(gl->vendor_str, "ATI", 4) ||
277         !nk_x11_stricmpn(gl->vendor_str, "AMD", 4))
278         gl->vendor = VENDOR_AMD;
279     else if (!nk_x11_stricmpn(gl->vendor_str, "NVIDIA", 6))
280         gl->vendor = VENDOR_NVIDIA;
281     else if (!nk_x11_stricmpn(gl->vendor_str, "Intel", 5))
282         gl->vendor = VENDOR_INTEL;
283     else gl->vendor = VENDOR_UNKNOWN;
284 
285     /* Extensions */
286     gl->glsl_available = (gl->version >= 2.0f);
287     if (gl->glsl_available) {
288         /* GLSL core in OpenGL > 2 */
289         glCreateShader = GL_EXT(glCreateShader);
290         glShaderSource = GL_EXT(glShaderSource);
291         glCompileShader = GL_EXT(glCompileShader);
292         glGetShaderiv = GL_EXT(glGetShaderiv);
293         glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog);
294         glDeleteShader = GL_EXT(glDeleteShader);
295         glCreateProgram = GL_EXT(glCreateProgram);
296         glAttachShader = GL_EXT(glAttachShader);
297         glDetachShader = GL_EXT(glDetachShader);
298         glLinkProgram = GL_EXT(glLinkProgram);
299         glUseProgram = GL_EXT(glUseProgram);
300         glGetProgramiv = GL_EXT(glGetProgramiv);
301         glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog);
302         glDeleteProgram = GL_EXT(glDeleteProgram);
303         glGetUniformLocation = GL_EXT(glGetUniformLocation);
304         glGetAttribLocation = GL_EXT(glGetAttribLocation);
305         glUniform1i = GL_EXT(glUniform1i);
306         glUniform1f = GL_EXT(glUniform1f);
307         glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv);
308         glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv);
309     }
310     gl->vertex_buffer_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_buffer_object");
311     if (gl->vertex_buffer_obj_available) {
312         /* GL_ARB_vertex_buffer_object */
313         glGenBuffers = GL_EXT(glGenBuffers);
314         glBindBuffer = GL_EXT(glBindBuffer);
315         glBufferData = GL_EXT(glBufferData);
316         glBufferSubData = GL_EXT(glBufferSubData);
317         glMapBuffer = GL_EXT(glMapBuffer);
318         glUnmapBuffer = GL_EXT(glUnmapBuffer);
319         glDeleteBuffers = GL_EXT(glDeleteBuffers);
320     }
321     gl->fragment_program_available = nk_x11_check_extension(gl, "GL_ARB_fragment_program");
322     if (gl->fragment_program_available) {
323         /* GL_ARB_vertex_program / GL_ARB_fragment_program  */
324         glVertexAttribPointer = GL_EXT(glVertexAttribPointer);
325         glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray);
326         glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray);
327     }
328     gl->vertex_array_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_array_object");
329     if (gl->vertex_array_obj_available) {
330         /* GL_ARB_vertex_array_object */
331         glGenVertexArrays = GL_EXT(glGenVertexArrays);
332         glBindVertexArray = GL_EXT(glBindVertexArray);
333         glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays);
334     }
335     gl->frame_buffer_object_available = nk_x11_check_extension(gl, "GL_ARB_framebuffer_object");
336     if (gl->frame_buffer_object_available) {
337         /* GL_ARB_framebuffer_object */
338         glGenerateMipmap = GL_EXT(glGenerateMipmap);
339     }
340     if (!gl->vertex_buffer_obj_available) {
341         fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n");
342         failed = nk_true;
343     }
344     if (!gl->fragment_program_available) {
345         fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n");
346         failed = nk_true;
347     }
348     if (!gl->vertex_array_obj_available) {
349         fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n");
350         failed = nk_true;
351     }
352     if (!gl->frame_buffer_object_available) {
353         fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n");
354         failed = nk_true;
355     }
356     return !failed;
357 }
358 #endif
359 
360 NK_API int
nk_x11_device_create(void)361 nk_x11_device_create(void)
362 {
363     GLint status;
364     static const GLchar *vertex_shader =
365         NK_SHADER_VERSION
366         "uniform mat4 ProjMtx;\n"
367         "in vec2 Position;\n"
368         "in vec2 TexCoord;\n"
369         "in vec4 Color;\n"
370         "out vec2 Frag_UV;\n"
371         "out vec4 Frag_Color;\n"
372         "void main() {\n"
373         "   Frag_UV = TexCoord;\n"
374         "   Frag_Color = Color;\n"
375         "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
376         "}\n";
377     static const GLchar *fragment_shader =
378         NK_SHADER_VERSION
379         "precision mediump float;\n"
380         "uniform sampler2D Texture;\n"
381         "in vec2 Frag_UV;\n"
382         "in vec4 Frag_Color;\n"
383         "out vec4 Out_Color;\n"
384         "void main(){\n"
385         "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
386         "}\n";
387 
388     struct nk_x11_device *dev = &x11.ogl;
389 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
390     if (!nk_load_opengl(&dev->info)) return 0;
391 #endif
392     nk_buffer_init_default(&dev->cmds);
393 
394     dev->prog = glCreateProgram();
395     dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
396     dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
397     glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
398     glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
399     glCompileShader(dev->vert_shdr);
400     glCompileShader(dev->frag_shdr);
401     glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
402     assert(status == GL_TRUE);
403     glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
404     assert(status == GL_TRUE);
405     glAttachShader(dev->prog, dev->vert_shdr);
406     glAttachShader(dev->prog, dev->frag_shdr);
407     glLinkProgram(dev->prog);
408     glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
409     assert(status == GL_TRUE);
410 
411     dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
412     dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
413     dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
414     dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
415     dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
416 
417     {
418         /* buffer setup */
419         GLsizei vs = sizeof(struct nk_x11_vertex);
420         size_t vp = offsetof(struct nk_x11_vertex, position);
421         size_t vt = offsetof(struct nk_x11_vertex, uv);
422         size_t vc = offsetof(struct nk_x11_vertex, col);
423 
424         glGenBuffers(1, &dev->vbo);
425         glGenBuffers(1, &dev->ebo);
426         glGenVertexArrays(1, &dev->vao);
427 
428         glBindVertexArray(dev->vao);
429         glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
430         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
431 
432         glEnableVertexAttribArray((GLuint)dev->attrib_pos);
433         glEnableVertexAttribArray((GLuint)dev->attrib_uv);
434         glEnableVertexAttribArray((GLuint)dev->attrib_col);
435 
436         glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
437         glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
438         glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
439     }
440 
441     glBindTexture(GL_TEXTURE_2D, 0);
442     glBindBuffer(GL_ARRAY_BUFFER, 0);
443     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
444     glBindVertexArray(0);
445     return 1;
446 }
447 
448 NK_INTERN void
nk_x11_device_upload_atlas(const void * image,int width,int height)449 nk_x11_device_upload_atlas(const void *image, int width, int height)
450 {
451     struct nk_x11_device *dev = &x11.ogl;
452     glGenTextures(1, &dev->font_tex);
453     glBindTexture(GL_TEXTURE_2D, dev->font_tex);
454     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
455     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
456     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
457                 GL_RGBA, GL_UNSIGNED_BYTE, image);
458 }
459 
460 NK_API void
nk_x11_device_destroy(void)461 nk_x11_device_destroy(void)
462 {
463     struct nk_x11_device *dev = &x11.ogl;
464     glDetachShader(dev->prog, dev->vert_shdr);
465     glDetachShader(dev->prog, dev->frag_shdr);
466     glDeleteShader(dev->vert_shdr);
467     glDeleteShader(dev->frag_shdr);
468     glDeleteProgram(dev->prog);
469     glDeleteTextures(1, &dev->font_tex);
470     glDeleteBuffers(1, &dev->vbo);
471     glDeleteBuffers(1, &dev->ebo);
472     nk_buffer_free(&dev->cmds);
473 }
474 
475 NK_API void
nk_x11_render(enum nk_anti_aliasing AA,int max_vertex_buffer,int max_element_buffer)476 nk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
477 {
478     int width, height;
479     XWindowAttributes attr;
480     struct nk_x11_device *dev = &x11.ogl;
481     GLfloat ortho[4][4] = {
482         {2.0f, 0.0f, 0.0f, 0.0f},
483         {0.0f,-2.0f, 0.0f, 0.0f},
484         {0.0f, 0.0f,-1.0f, 0.0f},
485         {-1.0f,1.0f, 0.0f, 1.0f},
486     };
487     XGetWindowAttributes(x11.dpy, x11.win, &attr);
488     width = attr.width;
489     height = attr.height;
490 
491     ortho[0][0] /= (GLfloat)width;
492     ortho[1][1] /= (GLfloat)height;
493 
494     /* setup global state */
495     glEnable(GL_BLEND);
496     glBlendEquation(GL_FUNC_ADD);
497     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
498     glDisable(GL_CULL_FACE);
499     glDisable(GL_DEPTH_TEST);
500     glEnable(GL_SCISSOR_TEST);
501     glActiveTexture(GL_TEXTURE0);
502 
503     /* setup program */
504     glUseProgram(dev->prog);
505     glUniform1i(dev->uniform_tex, 0);
506     glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
507     glViewport(0,0,(GLsizei)width,(GLsizei)height);
508     {
509         /* convert from command queue into draw list and draw to screen */
510         const struct nk_draw_command *cmd;
511         void *vertices, *elements;
512         const nk_draw_index *offset = NULL;
513         struct nk_buffer vbuf, ebuf;
514 
515         /* allocate vertex and element buffer */
516         glBindVertexArray(dev->vao);
517         glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
518         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
519 
520         glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
521         glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
522 
523         /* load draw vertices & elements directly into vertex + element buffer */
524         vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
525         elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
526         {
527             /* fill convert configuration */
528             struct nk_convert_config config;
529             static const struct nk_draw_vertex_layout_element vertex_layout[] = {
530                 {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},
531                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},
532                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},
533                 {NK_VERTEX_LAYOUT_END}
534             };
535             memset(&config, 0, sizeof(config));
536             config.vertex_layout = vertex_layout;
537             config.vertex_size = sizeof(struct nk_x11_vertex);
538             config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);
539             config.null = dev->null;
540             config.circle_segment_count = 22;
541             config.curve_segment_count = 22;
542             config.arc_segment_count = 22;
543             config.global_alpha = 1.0f;
544             config.shape_AA = AA;
545             config.line_AA = AA;
546 
547             /* setup buffers to load vertices and elements */
548             nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
549             nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
550             nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);
551         }
552         glUnmapBuffer(GL_ARRAY_BUFFER);
553         glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
554 
555         /* iterate over and execute each draw command */
556         nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)
557         {
558             if (!cmd->elem_count) continue;
559             glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
560             glScissor(
561                 (GLint)(cmd->clip_rect.x),
562                 (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
563                 (GLint)(cmd->clip_rect.w),
564                 (GLint)(cmd->clip_rect.h));
565             glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
566             offset += cmd->elem_count;
567         }
568         nk_clear(&x11.ctx);
569         nk_buffer_clear(&dev->cmds);
570     }
571 
572     /* default OpenGL state */
573     glUseProgram(0);
574     glBindBuffer(GL_ARRAY_BUFFER, 0);
575     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
576     glBindVertexArray(0);
577     glDisable(GL_BLEND);
578     glDisable(GL_SCISSOR_TEST);
579 }
580 
581 NK_API void
nk_x11_font_stash_begin(struct nk_font_atlas ** atlas)582 nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
583 {
584     nk_font_atlas_init_default(&x11.atlas);
585     nk_font_atlas_begin(&x11.atlas);
586     *atlas = &x11.atlas;
587 }
588 
589 NK_API void
nk_x11_font_stash_end(void)590 nk_x11_font_stash_end(void)
591 {
592     const void *image; int w, h;
593     image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
594     nk_x11_device_upload_atlas(image, w, h);
595     nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
596     if (x11.atlas.default_font)
597         nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
598 }
599 
600 NK_API int
nk_x11_handle_event(XEvent * evt)601 nk_x11_handle_event(XEvent *evt)
602 {
603     struct nk_context *ctx = &x11.ctx;
604 
605     /* optional grabbing behavior */
606     if (ctx->input.mouse.grab) {
607         XDefineCursor(x11.dpy, x11.win, x11.cursor);
608         ctx->input.mouse.grab = 0;
609     } else if (ctx->input.mouse.ungrab) {
610         XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
611             (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
612         XUndefineCursor(x11.dpy, x11.win);
613         ctx->input.mouse.ungrab = 0;
614     }
615 
616     if (evt->type == KeyPress || evt->type == KeyRelease)
617     {
618         /* Key handler */
619         int ret, down = (evt->type == KeyPress);
620         KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
621         if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
622         else if (*code == XK_Control_L || *code == XK_Control_R) nk_input_key(ctx, NK_KEY_CTRL, down);
623         else if (*code == XK_Delete)    nk_input_key(ctx, NK_KEY_DEL, down);
624         else if (*code == XK_Return)    nk_input_key(ctx, NK_KEY_ENTER, down);
625         else if (*code == XK_Tab)       nk_input_key(ctx, NK_KEY_TAB, down);
626         else if (*code == XK_Left)      nk_input_key(ctx, NK_KEY_LEFT, down);
627         else if (*code == XK_Right)     nk_input_key(ctx, NK_KEY_RIGHT, down);
628         else if (*code == XK_Up)        nk_input_key(ctx, NK_KEY_UP, down);
629         else if (*code == XK_Down)      nk_input_key(ctx, NK_KEY_DOWN, down);
630         else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
631         else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
632         else if (*code == XK_Page_Up)   nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
633         else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
634         else if (*code == XK_Home) {
635             nk_input_key(ctx, NK_KEY_TEXT_START, down);
636             nk_input_key(ctx, NK_KEY_SCROLL_START, down);
637         } else if (*code == XK_End) {
638             nk_input_key(ctx, NK_KEY_TEXT_END, down);
639             nk_input_key(ctx, NK_KEY_SCROLL_END, down);
640         } else {
641             if (*code == 'c' && (evt->xkey.state & ControlMask))
642                 nk_input_key(ctx, NK_KEY_COPY, down);
643             else if (*code == 'v' && (evt->xkey.state & ControlMask))
644                 nk_input_key(ctx, NK_KEY_PASTE, down);
645             else if (*code == 'x' && (evt->xkey.state & ControlMask))
646                 nk_input_key(ctx, NK_KEY_CUT, down);
647             else if (*code == 'z' && (evt->xkey.state & ControlMask))
648                 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
649             else if (*code == 'r' && (evt->xkey.state & ControlMask))
650                 nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
651             else if (*code == XK_Left && (evt->xkey.state & ControlMask))
652                 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
653             else if (*code == XK_Right && (evt->xkey.state & ControlMask))
654                 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
655             else if (*code == 'b' && (evt->xkey.state & ControlMask))
656                 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
657             else if (*code == 'e' && (evt->xkey.state & ControlMask))
658                 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
659             else {
660                 if (*code == 'i')
661                     nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
662                 else if (*code == 'r')
663                     nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
664                 if (down) {
665                     char buf[32];
666                     KeySym keysym = 0;
667                     if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
668                         nk_input_glyph(ctx, buf);
669                 }
670             }
671         }
672         XFree(code);
673         return 1;
674     } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
675         /* Button handler */
676         int down = (evt->type == ButtonPress);
677         const int x = evt->xbutton.x, y = evt->xbutton.y;
678         if (evt->xbutton.button == Button1) {
679             if (down) { /* Double-Click Button handler */
680                 long dt = nk_timestamp() - x11.last_button_click;
681                 if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
682                     nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
683                 x11.last_button_click = nk_timestamp();
684             } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
685             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
686         } else if (evt->xbutton.button == Button2)
687             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
688         else if (evt->xbutton.button == Button3)
689             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
690         else if (evt->xbutton.button == Button4)
691             nk_input_scroll(ctx, nk_vec2(0,1.0f));
692         else if (evt->xbutton.button == Button5)
693             nk_input_scroll(ctx, nk_vec2(0,-1.0f));
694         else return 0;
695         return 1;
696     } else if (evt->type == MotionNotify) {
697         /* Mouse motion handler */
698         const int x = evt->xmotion.x, y = evt->xmotion.y;
699         nk_input_motion(ctx, x, y);
700         if (ctx->input.mouse.grabbed) {
701             ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
702             ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
703             XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
704         }
705         return 1;
706     } else if (evt->type == KeymapNotify) {
707         XRefreshKeyboardMapping(&evt->xmapping);
708         return 1;
709     }
710     return 0;
711 }
712 
713 NK_API struct nk_context*
nk_x11_init(Display * dpy,Window win)714 nk_x11_init(Display *dpy, Window win)
715 {
716     if (!setlocale(LC_ALL,"")) return 0;
717     if (!XSupportsLocale()) return 0;
718     if (!XSetLocaleModifiers("@im=none")) return 0;
719     if (!nk_x11_device_create()) return 0;
720 
721     x11.dpy = dpy;
722     x11.win = win;
723 
724     /* create invisible cursor */
725     {static XColor dummy; char data[1] = {0};
726     Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
727     if (blank == None) return 0;
728     x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
729     XFreePixmap(dpy, blank);}
730 
731     nk_init_default(&x11.ctx, 0);
732     return &x11.ctx;
733 }
734 
735 NK_API void
nk_x11_shutdown(void)736 nk_x11_shutdown(void)
737 {
738     nk_font_atlas_clear(&x11.atlas);
739     nk_free(&x11.ctx);
740     nk_x11_device_destroy();
741     XFreeCursor(x11.dpy, x11.cursor);
742     memset(&x11, 0, sizeof(x11));
743 }
744 
745 #endif
746