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 fullfill 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 NK_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 }
570
571 /* default OpenGL state */
572 glUseProgram(0);
573 glBindBuffer(GL_ARRAY_BUFFER, 0);
574 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
575 glBindVertexArray(0);
576 glDisable(GL_BLEND);
577 glDisable(GL_SCISSOR_TEST);
578 }
579
580 NK_API void
nk_x11_font_stash_begin(struct nk_font_atlas ** atlas)581 nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
582 {
583 nk_font_atlas_init_default(&x11.atlas);
584 nk_font_atlas_begin(&x11.atlas);
585 *atlas = &x11.atlas;
586 }
587
588 NK_API void
nk_x11_font_stash_end(void)589 nk_x11_font_stash_end(void)
590 {
591 const void *image; int w, h;
592 image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
593 nk_x11_device_upload_atlas(image, w, h);
594 nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
595 if (x11.atlas.default_font)
596 nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
597 }
598
599 NK_API int
nk_x11_handle_event(XEvent * evt)600 nk_x11_handle_event(XEvent *evt)
601 {
602 struct nk_context *ctx = &x11.ctx;
603
604 /* optional grabbing behavior */
605 if (ctx->input.mouse.grab) {
606 XDefineCursor(x11.dpy, x11.win, x11.cursor);
607 ctx->input.mouse.grab = 0;
608 } else if (ctx->input.mouse.ungrab) {
609 XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
610 (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
611 XUndefineCursor(x11.dpy, x11.win);
612 ctx->input.mouse.ungrab = 0;
613 }
614
615 if (evt->type == KeyPress || evt->type == KeyRelease)
616 {
617 /* Key handler */
618 int ret, down = (evt->type == KeyPress);
619 KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
620 if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
621 else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down);
622 else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down);
623 else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down);
624 else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down);
625 else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down);
626 else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down);
627 else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
628 else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
629 else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
630 else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
631 else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
632 else if (*code == XK_Home) {
633 nk_input_key(ctx, NK_KEY_TEXT_START, down);
634 nk_input_key(ctx, NK_KEY_SCROLL_START, down);
635 } else if (*code == XK_End) {
636 nk_input_key(ctx, NK_KEY_TEXT_END, down);
637 nk_input_key(ctx, NK_KEY_SCROLL_END, down);
638 } else {
639 if (*code == 'c' && (evt->xkey.state & ControlMask))
640 nk_input_key(ctx, NK_KEY_COPY, down);
641 else if (*code == 'v' && (evt->xkey.state & ControlMask))
642 nk_input_key(ctx, NK_KEY_PASTE, down);
643 else if (*code == 'x' && (evt->xkey.state & ControlMask))
644 nk_input_key(ctx, NK_KEY_CUT, down);
645 else if (*code == 'z' && (evt->xkey.state & ControlMask))
646 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
647 else if (*code == 'r' && (evt->xkey.state & ControlMask))
648 nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
649 else if (*code == XK_Left && (evt->xkey.state & ControlMask))
650 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
651 else if (*code == XK_Right && (evt->xkey.state & ControlMask))
652 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
653 else if (*code == 'b' && (evt->xkey.state & ControlMask))
654 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
655 else if (*code == 'e' && (evt->xkey.state & ControlMask))
656 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
657 else {
658 if (*code == 'i')
659 nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
660 else if (*code == 'r')
661 nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
662 if (down) {
663 char buf[32];
664 KeySym keysym = 0;
665 if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
666 nk_input_glyph(ctx, buf);
667 }
668 }
669 }
670 XFree(code);
671 return 1;
672 } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
673 /* Button handler */
674 int down = (evt->type == ButtonPress);
675 const int x = evt->xbutton.x, y = evt->xbutton.y;
676 if (evt->xbutton.button == Button1) {
677 if (down) { /* Double-Click Button handler */
678 long dt = nk_timestamp() - x11.last_button_click;
679 if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
680 nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
681 x11.last_button_click = nk_timestamp();
682 } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
683 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
684 } else if (evt->xbutton.button == Button2)
685 nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
686 else if (evt->xbutton.button == Button3)
687 nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
688 else if (evt->xbutton.button == Button4)
689 nk_input_scroll(ctx, nk_vec2(0,1.0f));
690 else if (evt->xbutton.button == Button5)
691 nk_input_scroll(ctx, nk_vec2(0,-1.0f));
692 else return 0;
693 return 1;
694 } else if (evt->type == MotionNotify) {
695 /* Mouse motion handler */
696 const int x = evt->xmotion.x, y = evt->xmotion.y;
697 nk_input_motion(ctx, x, y);
698 if (ctx->input.mouse.grabbed) {
699 ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
700 ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
701 XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
702 }
703 return 1;
704 } else if (evt->type == KeymapNotify) {
705 XRefreshKeyboardMapping(&evt->xmapping);
706 return 1;
707 }
708 return 0;
709 }
710
711 NK_API struct nk_context*
nk_x11_init(Display * dpy,Window win)712 nk_x11_init(Display *dpy, Window win)
713 {
714 if (!setlocale(LC_ALL,"")) return 0;
715 if (!XSupportsLocale()) return 0;
716 if (!XSetLocaleModifiers("@im=none")) return 0;
717 if (!nk_x11_device_create()) return 0;
718
719 x11.dpy = dpy;
720 x11.win = win;
721
722 /* create invisible cursor */
723 {static XColor dummy; char data[1] = {0};
724 Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
725 if (blank == None) return 0;
726 x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
727 XFreePixmap(dpy, blank);}
728
729 nk_init_default(&x11.ctx, 0);
730 return &x11.ctx;
731 }
732
733 NK_API void
nk_x11_shutdown(void)734 nk_x11_shutdown(void)
735 {
736 nk_font_atlas_clear(&x11.atlas);
737 nk_free(&x11.ctx);
738 nk_x11_device_destroy();
739 XFreeCursor(x11.dpy, x11.cursor);
740 memset(&x11, 0, sizeof(x11));
741 }
742
743 #endif
744