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_GL2_H_
14 #define NK_SFML_GL2_H_
15 
16 #include <SFML/Window.hpp>
17 
18 NK_API struct nk_context*   nk_sfml_init(sf::Window* window);
19 NK_API void                 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
20 NK_API void                 nk_sfml_font_stash_end(void);
21 NK_API int                  nk_sfml_handle_event(sf::Event* event);
22 NK_API void                 nk_sfml_render(enum nk_anti_aliasing);
23 NK_API void                 nk_sfml_shutdown(void);
24 
25 #endif
26 /*
27  * ==============================================================
28  *
29  *                          IMPLEMENTATION
30  *
31  * ===============================================================
32  */
33  #ifdef NK_SFML_GL2_IMPLEMENTATION
34 
35 struct nk_sfml_device {
36     struct nk_buffer cmds;
37     struct nk_draw_null_texture null;
38     GLuint font_tex;
39 };
40 
41 struct nk_sfml_vertex {
42     float position[2];
43     float uv[2];
44     nk_byte col[4];
45 };
46 
47 static struct nk_sfml {
48     sf::Window* window;
49     struct nk_sfml_device ogl;
50     struct nk_context ctx;
51     struct nk_font_atlas atlas;
52 } sfml;
53 
54 NK_INTERN void
nk_sfml_device_upload_atlas(const void * image,int width,int height)55 nk_sfml_device_upload_atlas(const void* image, int width, int height)
56 {
57     struct nk_sfml_device* dev = &sfml.ogl;
58     glGenTextures(1, &dev->font_tex);
59     glBindTexture(GL_TEXTURE_2D, dev->font_tex);
60     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
61     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
62     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
63                 GL_RGBA, GL_UNSIGNED_BYTE, image);
64 }
65 
66 NK_API void
nk_sfml_render(enum nk_anti_aliasing AA)67 nk_sfml_render(enum nk_anti_aliasing AA)
68 {
69     /* setup global state */
70     struct nk_sfml_device* dev = &sfml.ogl;
71 
72     int window_width = sfml.window->getSize().x;
73     int window_height = sfml.window->getSize().y;
74 
75     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
76     glDisable(GL_CULL_FACE);
77     glDisable(GL_DEPTH_TEST);
78     glEnable(GL_SCISSOR_TEST);
79     glEnable(GL_BLEND);
80     glEnable(GL_TEXTURE_2D);
81     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
82 
83     glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height);
84     glMatrixMode(GL_TEXTURE);
85     glPushMatrix();
86     glLoadIdentity();
87     glMatrixMode(GL_PROJECTION);
88     glPushMatrix();
89     glLoadIdentity();
90     glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);
91     glMatrixMode(GL_MODELVIEW);
92     glPushMatrix();
93     glLoadIdentity();
94 
95     glEnableClientState(GL_VERTEX_ARRAY);
96     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
97     glEnableClientState(GL_COLOR_ARRAY);
98     {
99         GLsizei vs = sizeof(struct nk_sfml_vertex);
100         size_t vp = NK_OFFSETOF(struct nk_sfml_vertex, position);
101         size_t vt = NK_OFFSETOF(struct nk_sfml_vertex, uv);
102         size_t vc = NK_OFFSETOF(struct nk_sfml_vertex, col);
103 
104         /* convert from command queue into draw  list and draw to screen */
105         const struct nk_draw_command* cmd;
106         const nk_draw_index* offset = NULL;
107         struct nk_buffer vbuf, ebuf;
108 
109         /* fill converting configuration */
110         struct nk_convert_config config;
111         static const struct nk_draw_vertex_layout_element vertex_layout[] = {
112             {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},
113             {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
114             {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
115             {NK_VERTEX_LAYOUT_END}
116         };
117         memset(&config, 0, sizeof(config));
118         config.vertex_layout = vertex_layout;
119         config.vertex_size = sizeof(struct nk_sfml_vertex);
120         config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);
121         config.null = dev->null;
122         config.circle_segment_count = 22;
123         config.curve_segment_count = 22;
124         config.arc_segment_count = 22;
125         config.global_alpha = 1.0f;
126         config.shape_AA = AA;
127         config.line_AA = AA;
128 
129         /* convert shapes into vertices */
130         nk_buffer_init_default(&vbuf);
131         nk_buffer_init_default(&ebuf);
132         nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);
133 
134         /* setup vertex buffer pointer */
135         const void* vertices = nk_buffer_memory_const(&vbuf);
136         glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
137         glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
138         glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));
139 
140         /* iterate over and execute each draw command */
141         offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
142         nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)
143         {
144             if(!cmd->elem_count) continue;
145             glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
146             glScissor(
147                 (GLint)(cmd->clip_rect.x),
148                 (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
149                 (GLint)(cmd->clip_rect.w),
150                 (GLint)(cmd->clip_rect.h));
151             glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
152             offset += cmd->elem_count;
153         }
154         nk_clear(&sfml.ctx);
155         nk_buffer_clear(&dev->cmds);
156         nk_buffer_free(&vbuf);
157         nk_buffer_free(&ebuf);
158     }
159 
160     /* default OpenGL state */
161     glDisableClientState(GL_VERTEX_ARRAY);
162     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
163     glDisableClientState(GL_COLOR_ARRAY);
164 
165     glDisable(GL_CULL_FACE);
166     glDisable(GL_DEPTH_TEST);
167     glDisable(GL_SCISSOR_TEST);
168     glDisable(GL_BLEND);
169     glDisable(GL_TEXTURE_2D);
170 
171     glBindTexture(GL_TEXTURE_2D, 0);
172     glMatrixMode(GL_TEXTURE);
173     glPopMatrix();
174     glMatrixMode(GL_MODELVIEW);
175     glPopMatrix();
176     glMatrixMode(GL_PROJECTION);
177     glPopMatrix();
178     glPopAttrib();
179 }
180 
181 static void
nk_sfml_clipboard_paste(nk_handle usr,struct nk_text_edit * edit)182 nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
183 {
184 #if 0
185     /* Not Implemented in SFML */
186     sf::Clipboard clipboard(sfml.window);
187     const char* text = clipboard.getText();
188 
189     if(text)
190         nk_textedit_paste(edit, text, nk_strlen(text));
191         (void)usr;
192 #else
193     NK_UNUSED(usr);
194     NK_UNUSED(edit);
195 #endif
196 }
197 
198 static void
nk_sfml_clipboard_copy(nk_handle usr,const char * text,int len)199 nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
200 {
201 #if 0
202     char* str = 0;
203     (void)usr;
204     if(!len) return;
205     str = (char*)malloc((size_t)len+1);
206     if(!str) return;
207     memcpy(str, text, (size_t)len);
208     str[len] = '\0';
209 
210     /* Not Implemented in SFML */
211     sf::Clipboard clipboard(sfml.window);
212     clipboard.setText(str);
213     free(str);
214 #else
215     NK_UNUSED(usr);
216     NK_UNUSED(text);
217     NK_UNUSED(len);
218 #endif
219 }
220 
221 NK_API struct nk_context*
nk_sfml_init(sf::Window * window)222 nk_sfml_init(sf::Window* window)
223 {
224     sfml.window = window;
225     nk_init_default(&sfml.ctx, 0);
226     sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
227     sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
228     sfml.ctx.clip.userdata = nk_handle_ptr(0);
229     nk_buffer_init_default(&sfml.ogl.cmds);
230     return &sfml.ctx;
231 }
232 
233 NK_API void
nk_sfml_font_stash_begin(struct nk_font_atlas ** atlas)234 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
235 {
236     nk_font_atlas_init_default(&sfml.atlas);
237     nk_font_atlas_begin(&sfml.atlas);
238     *atlas = &sfml.atlas;
239 }
240 
241 NK_API void
nk_sfml_font_stash_end()242 nk_sfml_font_stash_end()
243 {
244     int w, h;
245     const void* img;
246     img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
247     nk_sfml_device_upload_atlas(img, w, h);
248     nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
249     if(sfml.atlas.default_font)
250         nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
251 }
252 
253 NK_API int
nk_sfml_handle_event(sf::Event * evt)254 nk_sfml_handle_event(sf::Event* evt)
255 {
256     struct nk_context* ctx = &sfml.ctx;
257     /* optional grabbing behavior */
258     if(ctx->input.mouse.grab)
259         ctx->input.mouse.grab = 0;
260     else if(ctx->input.mouse.ungrab) {
261         int x = (int)ctx->input.mouse.prev.x;
262         int y = (int)ctx->input.mouse.prev.y;
263         sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
264         ctx->input.mouse.ungrab = 0;
265     }
266     if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
267     {
268         int down = evt->type == sf::Event::KeyPressed;
269         sf::Keyboard::Key key = evt->key.code;
270         if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
271             nk_input_key(ctx, NK_KEY_SHIFT, down);
272         else if(key == sf::Keyboard::Delete)
273             nk_input_key(ctx, NK_KEY_DEL, down);
274         else if(key == sf::Keyboard::Return)
275             nk_input_key(ctx, NK_KEY_ENTER, down);
276         else if(key == sf::Keyboard::Tab)
277             nk_input_key(ctx, NK_KEY_TAB, down);
278         else if(key == sf::Keyboard::BackSpace)
279             nk_input_key(ctx, NK_KEY_BACKSPACE, down);
280         else if(key == sf::Keyboard::Home) {
281             nk_input_key(ctx, NK_KEY_TEXT_START, down);
282             nk_input_key(ctx, NK_KEY_SCROLL_START, down);
283         } else if(key == sf::Keyboard::End) {
284             nk_input_key(ctx, NK_KEY_TEXT_END, down);
285             nk_input_key(ctx, NK_KEY_SCROLL_END, down);
286         } else if(key == sf::Keyboard::PageDown)
287             nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
288         else if(key == sf::Keyboard::PageUp)
289             nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
290         else if(key == sf::Keyboard::Z)
291             nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
292         else if(key == sf::Keyboard::R)
293             nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
294         else if(key == sf::Keyboard::C)
295             nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
296         else if(key == sf::Keyboard::V)
297             nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
298         else if(key == sf::Keyboard::X)
299             nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
300         else if(key == sf::Keyboard::B)
301             nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
302         else if(key == sf::Keyboard::E)
303             nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
304         else if(key == sf::Keyboard::Up)
305             nk_input_key(ctx, NK_KEY_UP, down);
306         else if(key == sf::Keyboard::Down)
307             nk_input_key(ctx, NK_KEY_DOWN, down);
308         else if(key == sf::Keyboard::Left) {
309             if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
310                 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
311             else nk_input_key(ctx, NK_KEY_LEFT, down);
312         } else if(key == sf::Keyboard::Right) {
313             if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
314                 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
315             else nk_input_key(ctx, NK_KEY_RIGHT, down);
316         } else return 0;
317         return 1;
318     } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
319         int down = evt->type == sf::Event::MouseButtonPressed;
320         const int x = evt->mouseButton.x, y = evt->mouseButton.y;
321         if(evt->mouseButton.button == sf::Mouse::Left)
322             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
323         if(evt->mouseButton.button == sf::Mouse::Middle)
324             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
325         if(evt->mouseButton.button == sf::Mouse::Right)
326             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
327         else return 0;
328         return 1;
329     } else if(evt->type == sf::Event::MouseMoved) {
330         nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
331         return 1;
332     } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
333         int down = evt->type == sf::Event::TouchBegan;
334         const int x = evt->touch.x, y = evt->touch.y;
335 		ctx->input.mouse.pos.x = x;
336 		ctx->input.mouse.pos.y = y;
337         nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
338         return 1;
339     } else if(evt->type == sf::Event::TouchMoved) {
340         if(ctx->input.mouse.grabbed) {
341             int x = (int)ctx->input.mouse.prev.x;
342             int y = (int)ctx->input.mouse.prev.y;
343             nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
344         } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
345         return 1;
346     } else if(evt->type == sf::Event::TextEntered) {
347         nk_input_unicode(ctx, evt->text.unicode);
348         return 1;
349     } else if(evt->type == sf::Event::MouseWheelScrolled) {
350         nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
351         return 1;
352     }
353     return 0;
354 }
355 
356 NK_API
nk_sfml_shutdown(void)357 void nk_sfml_shutdown(void)
358 {
359     struct nk_sfml_device* dev = &sfml.ogl;
360     nk_font_atlas_clear(&sfml.atlas);
361     nk_free(&sfml.ctx);
362     glDeleteTextures(1, &dev->font_tex);
363     nk_buffer_free(&dev->cmds);
364     memset(&sfml, 0, sizeof(sfml));
365 }
366 
367 #endif
368