1 /*
2 * Nuklear - 1.32.0 - 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_SFML_GL3_H_
14 #define NK_SFML_GL3_H_
15
16 /* Feel free to edit here and include your own extension wrangler */
17 #include <glad/glad.h>
18 /* I use GLAD but you can use GLEW or what you like */
19
20 #include <SFML/Window.hpp>
21
22 NK_API struct nk_context* nk_sfml_init(sf::Window* window);
23 NK_API void nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
24 NK_API void nk_sfml_font_stash_end(void);
25 NK_API int nk_sfml_handle_event(sf::Event* event);
26 NK_API void nk_sfml_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
27 NK_API void nk_sfml_shutdown(void);
28
29 NK_API void nk_sfml_device_create(void);
30 NK_API void nk_sfml_device_destroy(void);
31
32 #endif
33 /*
34 * ==============================================================
35 *
36 * IMPLEMENTATION
37 *
38 * ===============================================================
39 */
40 #ifdef NK_SFML_GL3_IMPLEMENTATION
41
42 #include <string>
43
44 struct nk_sfml_device {
45 struct nk_buffer cmds;
46 struct nk_draw_null_texture null;
47 GLuint vbo, vao, ebo;
48 GLuint prog;
49 GLuint vert_shdr;
50 GLuint frag_shdr;
51 GLint attrib_pos;
52 GLint attrib_uv;
53 GLint attrib_col;
54 GLint uniform_tex;
55 GLint uniform_proj;
56 GLuint font_tex;
57 };
58 struct nk_sfml_vertex {
59 float position[2];
60 float uv[2];
61 nk_byte col[4];
62 };
63 static struct nk_sfml {
64 sf::Window* window;
65 struct nk_sfml_device ogl;
66 struct nk_context ctx;
67 struct nk_font_atlas atlas;
68 } sfml;
69
70 #ifdef __APPLE__
71 #define NK_SHADER_VERSION "#version 150\n"
72 #else
73 #define NK_SHADER_VERSION "#version 300 es\n"
74 #endif
75
76 NK_API void
nk_sfml_device_create(void)77 nk_sfml_device_create(void)
78 {
79 GLint status;
80 static const GLchar* vertex_shader =
81 NK_SHADER_VERSION
82 "uniform mat4 ProjMtx;\n"
83 "in vec2 Position;\n"
84 "in vec2 TexCoord;\n"
85 "in vec4 Color;\n"
86 "out vec2 Frag_UV;\n"
87 "out vec4 Frag_Color;\n"
88 "void main() {\n"
89 " Frag_UV = TexCoord;\n"
90 " Frag_Color = Color;\n"
91 " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
92 "}\n";
93 static const GLchar *fragment_shader =
94 NK_SHADER_VERSION
95 "precision mediump float;\n"
96 "uniform sampler2D Texture;\n"
97 "in vec2 Frag_UV;\n"
98 "in vec4 Frag_Color;\n"
99 "out vec4 Out_Color;\n"
100 "void main(){\n"
101 " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
102 "}\n";
103
104 struct nk_sfml_device* dev = &sfml.ogl;
105 nk_buffer_init_default(&dev->cmds);
106
107 dev->prog = glCreateProgram();
108 dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
109 dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
110
111 glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
112 glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
113 glCompileShader(dev->vert_shdr);
114 glCompileShader(dev->frag_shdr);
115
116 glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
117 assert(status == GL_TRUE);
118
119 glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
120 assert(status == GL_TRUE);
121
122 glAttachShader(dev->prog, dev->vert_shdr);
123 glAttachShader(dev->prog, dev->frag_shdr);
124 glLinkProgram(dev->prog);
125
126 glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
127 assert(status == GL_TRUE);
128
129 dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
130 dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
131 dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
132 dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
133 dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
134 {
135 /* buffer setup */
136 GLsizei vs = sizeof(struct nk_sfml_vertex);
137 size_t vp = offsetof(struct nk_sfml_vertex, position);
138 size_t vt = offsetof(struct nk_sfml_vertex, uv);
139 size_t vc = offsetof(struct nk_sfml_vertex, col);
140
141 glGenBuffers(1, &dev->vbo);
142 glGenBuffers(1, &dev->ebo);
143 glGenVertexArrays(1, &dev->vao);
144
145 glBindVertexArray(dev->vao);
146 glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
147 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
148
149 glEnableVertexAttribArray((GLuint)dev->attrib_pos);
150 glEnableVertexAttribArray((GLuint)dev->attrib_uv);
151 glEnableVertexAttribArray((GLuint)dev->attrib_col);
152
153 glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
154 glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
155 glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
156 }
157 glBindTexture(GL_TEXTURE_2D, 0);
158 glBindBuffer(GL_ARRAY_BUFFER, 0);
159 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
160 glBindVertexArray(0);
161 }
162
163 NK_API void
nk_sfml_device_destroy(void)164 nk_sfml_device_destroy(void)
165 {
166 struct nk_sfml_device* dev = &sfml.ogl;
167
168 glDetachShader(dev->prog, dev->vert_shdr);
169 glDetachShader(dev->prog, dev->frag_shdr);
170 glDeleteShader(dev->vert_shdr);
171 glDeleteShader(dev->vert_shdr);
172 glDeleteProgram(dev->prog);
173 glDeleteTextures(1, &dev->font_tex);
174 glDeleteBuffers(1, &dev->vbo);
175 glDeleteBuffers(1, &dev->ebo);
176 nk_buffer_free(&dev->cmds);
177 }
178
179 NK_INTERN void
nk_sfml_device_upload_atlas(const void * image,int width,int height)180 nk_sfml_device_upload_atlas(const void* image, int width, int height)
181 {
182 struct nk_sfml_device* dev = &sfml.ogl;
183 glGenTextures(1, &dev->font_tex);
184 glBindTexture(GL_TEXTURE_2D, dev->font_tex);
185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
186 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
187 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
188 GL_RGBA, GL_UNSIGNED_BYTE, image);
189 }
190
191 NK_API void
nk_sfml_render(enum nk_anti_aliasing AA,int max_vertex_buffer,int max_element_buffer)192 nk_sfml_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
193 {
194 /* setup global state */
195 struct nk_sfml_device* dev = &sfml.ogl;
196 int window_width = sfml.window->getSize().x;
197 int window_height = sfml.window->getSize().y;
198 GLfloat ortho[4][4] = {
199 {2.0f, 0.0f, 0.0f, 0.0f},
200 {0.0f,-2.0f, 0.0f, 0.0f},
201 {0.0f, 0.0f,-1.0f, 0.0f},
202 {-1.0f,1.0f, 0.0f, 1.0f},
203 };
204 ortho[0][0] /= (GLfloat)window_width;
205 ortho[1][1] /= (GLfloat)window_height;
206
207 glViewport(0, 0, window_width, window_height);
208 glEnable(GL_BLEND);
209 glBlendEquation(GL_FUNC_ADD);
210 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
211 glDisable(GL_CULL_FACE);
212 glDisable(GL_DEPTH_TEST);
213 glEnable(GL_SCISSOR_TEST);
214 glActiveTexture(GL_TEXTURE0);
215
216 /* setup program */
217 glUseProgram(dev->prog);
218 glUniform1i(dev->uniform_tex, 0);
219 glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
220 {
221 /* convert from command queue into draw list and draw to screen */
222 const struct nk_draw_command *cmd;
223 void *vertices, *elements;
224 const nk_draw_index *offset = NULL;
225
226 /* allocate vertex and element buffer */
227 glBindVertexArray(dev->vao);
228 glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
229 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
230
231 glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
232 glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
233
234 /* load vertices/elements directly into vertex/element buffer */
235 vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
236 elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
237 {
238 /* fill convert configuration */
239 struct nk_convert_config config;
240 static const struct nk_draw_vertex_layout_element vertex_layout[] = {
241 {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},
242 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
243 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
244 {NK_VERTEX_LAYOUT_END}
245 };
246
247 NK_MEMSET(&config, 0, sizeof(config));
248 config.vertex_layout = vertex_layout;
249 config.vertex_size = sizeof(struct nk_sfml_vertex);
250 config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);
251 config.null = dev->null;
252 config.circle_segment_count = 22;
253 config.curve_segment_count = 22;
254 config.arc_segment_count = 22;
255 config.global_alpha = 1.0f;
256 config.shape_AA = AA;
257 config.line_AA = AA;
258
259 /* setup buffers to load vertices and elements */
260 struct nk_buffer vbuf, ebuf;
261 nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
262 nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
263 nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);
264 }
265 glUnmapBuffer(GL_ARRAY_BUFFER);
266 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
267
268 /* iterate over and execute each draw command */
269 nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)
270 {
271 if (!cmd->elem_count) continue;
272 glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
273 glScissor(
274 (GLint)(cmd->clip_rect.x),
275 (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
276 (GLint)(cmd->clip_rect.w),
277 (GLint)(cmd->clip_rect.h));
278 glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
279 offset += cmd->elem_count;
280 }
281 nk_clear(&sfml.ctx);
282 }
283 glUseProgram(0);
284 glBindBuffer(GL_ARRAY_BUFFER, 0);
285 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
286 glBindVertexArray(0);
287 glDisable(GL_BLEND);
288 glDisable(GL_SCISSOR_TEST);
289 }
290
291 static void
nk_sfml_clipboard_paste(nk_handle usr,struct nk_text_edit * edit)292 nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
293 {
294 #if 0
295 /* Not Implemented in SFML */
296 (void)usr;
297 sf::Clipboard clipboard(sfml.window);
298 const char* text = clipboard.getText();
299 if(text) nk_textedit_paste(edit, text, nk_strlen(text));
300 #endif
301 }
302 static void
nk_sfml_clipboard_copy(nk_handle usr,const char * text,int len)303 nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
304 {
305 #if 0
306 char* str = 0;
307 (void)usr;
308 if(!len) return;
309 str = (char*)malloc((size_t)len+1);
310 if(!str) return;
311 memcpy(str, text, (size_t)len);
312 str[len] = '\0';
313
314 /* Not Implemented in SFML */
315 sf::Clipboard clipboard(sfml.window);
316 clipboard.setText(str);
317 free(str);
318 #endif
319 }
320
321 NK_API struct nk_context*
nk_sfml_init(sf::Window * window)322 nk_sfml_init(sf::Window* window)
323 {
324 sfml.window = window;
325 nk_init_default(&sfml.ctx, 0);
326 sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
327 sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
328 sfml.ctx.clip.userdata = nk_handle_ptr(0);
329 nk_sfml_device_create();
330 return &sfml.ctx;
331 }
332
333 NK_API void
nk_sfml_font_stash_begin(struct nk_font_atlas ** atlas)334 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
335 {
336 nk_font_atlas_init_default(&sfml.atlas);
337 nk_font_atlas_begin(&sfml.atlas);
338 *atlas = &sfml.atlas;
339 }
340
341 NK_API void
nk_sfml_font_stash_end()342 nk_sfml_font_stash_end()
343 {
344 const void* image;
345 int w, h;
346 image = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
347 nk_sfml_device_upload_atlas(image, w, h);
348 nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
349 if(sfml.atlas.default_font)
350 nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
351 }
352
353 NK_API int
nk_sfml_handle_event(sf::Event * evt)354 nk_sfml_handle_event(sf::Event* evt)
355 {
356 struct nk_context* ctx = &sfml.ctx;
357 /* optional grabbing behavior */
358 if(ctx->input.mouse.grab)
359 ctx->input.mouse.grab = 0;
360 else if(ctx->input.mouse.ungrab) {
361 int x = (int)ctx->input.mouse.prev.x;
362 int y = (int)ctx->input.mouse.prev.y;
363 sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
364 ctx->input.mouse.ungrab = 0;
365 }
366 if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
367 {
368 int down = evt->type == sf::Event::KeyPressed;
369 sf::Keyboard::Key key = evt->key.code;
370 if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
371 nk_input_key(ctx, NK_KEY_SHIFT, down);
372 else if(key == sf::Keyboard::Delete)
373 nk_input_key(ctx, NK_KEY_DEL, down);
374 else if(key == sf::Keyboard::Return)
375 nk_input_key(ctx, NK_KEY_ENTER, down);
376 else if(key == sf::Keyboard::Tab)
377 nk_input_key(ctx, NK_KEY_TAB, down);
378 else if(key == sf::Keyboard::BackSpace)
379 nk_input_key(ctx, NK_KEY_BACKSPACE, down);
380 else if(key == sf::Keyboard::Home) {
381 nk_input_key(ctx, NK_KEY_TEXT_START, down);
382 nk_input_key(ctx, NK_KEY_SCROLL_START, down);
383 } else if(key == sf::Keyboard::End) {
384 nk_input_key(ctx, NK_KEY_TEXT_END, down);
385 nk_input_key(ctx, NK_KEY_SCROLL_END, down);
386 } else if(key == sf::Keyboard::PageDown)
387 nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
388 else if(key == sf::Keyboard::PageUp)
389 nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
390 else if(key == sf::Keyboard::Z)
391 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
392 else if(key == sf::Keyboard::R)
393 nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
394 else if(key == sf::Keyboard::C)
395 nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
396 else if(key == sf::Keyboard::V)
397 nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
398 else if(key == sf::Keyboard::X)
399 nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
400 else if(key == sf::Keyboard::B)
401 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
402 else if(key == sf::Keyboard::E)
403 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
404 else if(key == sf::Keyboard::Up)
405 nk_input_key(ctx, NK_KEY_UP, down);
406 else if(key == sf::Keyboard::Down)
407 nk_input_key(ctx, NK_KEY_DOWN, down);
408 else if(key == sf::Keyboard::Left) {
409 if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
410 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
411 else nk_input_key(ctx, NK_KEY_LEFT, down);
412 } else if(key == sf::Keyboard::Right) {
413 if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
414 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
415 else nk_input_key(ctx, NK_KEY_RIGHT, down);
416 } else return 0;
417 return 1;
418 } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
419 int down = evt->type == sf::Event::MouseButtonPressed;
420 const int x = evt->mouseButton.x, y = evt->mouseButton.y;
421 if(evt->mouseButton.button == sf::Mouse::Left)
422 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
423 if(evt->mouseButton.button == sf::Mouse::Middle)
424 nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
425 if(evt->mouseButton.button == sf::Mouse::Right)
426 nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
427 else return 0;
428 return 1;
429 } else if(evt->type == sf::Event::MouseMoved) {
430 nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
431 return 1;
432 } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
433 int down = evt->type == sf::Event::TouchBegan;
434 const int x = evt->touch.x, y = evt->touch.y;
435 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
436 return 1;
437 } else if(evt->type == sf::Event::TouchMoved) {
438 if(ctx->input.mouse.grabbed) {
439 int x = (int)ctx->input.mouse.prev.x;
440 int y = (int)ctx->input.mouse.prev.y;
441 nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
442 } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
443 return 1;
444 } else if(evt->type == sf::Event::TextEntered) {
445 nk_input_unicode(ctx, evt->text.unicode);
446 return 1;
447 } else if(evt->type == sf::Event::MouseWheelScrolled) {
448 nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
449 return 1;
450 }
451 return 0;
452 }
453
454 NK_API
nk_sfml_shutdown()455 void nk_sfml_shutdown()
456 {
457 nk_font_atlas_clear(&sfml.atlas);
458 nk_free(&sfml.ctx);
459 nk_sfml_device_destroy();
460 memset(&sfml, 0, sizeof(sfml));
461 }
462
463 #endif
464