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 = offsetof(struct nk_sfml_vertex, position);
101 size_t vt = offsetof(struct nk_sfml_vertex, uv);
102 size_t vc = 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 NK_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_free(&vbuf);
156 nk_buffer_free(&ebuf);
157 }
158
159 /* default OpenGL state */
160 glDisableClientState(GL_VERTEX_ARRAY);
161 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
162 glDisableClientState(GL_COLOR_ARRAY);
163
164 glDisable(GL_CULL_FACE);
165 glDisable(GL_DEPTH_TEST);
166 glDisable(GL_SCISSOR_TEST);
167 glDisable(GL_BLEND);
168 glDisable(GL_TEXTURE_2D);
169
170 glBindTexture(GL_TEXTURE_2D, 0);
171 glMatrixMode(GL_TEXTURE);
172 glPopMatrix();
173 glMatrixMode(GL_MODELVIEW);
174 glPopMatrix();
175 glMatrixMode(GL_PROJECTION);
176 glPopMatrix();
177 glPopAttrib();
178 }
179
180 static void
nk_sfml_clipboard_paste(nk_handle usr,struct nk_text_edit * edit)181 nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
182 {
183 #if 0
184 /* Not Implemented in SFML */
185 sf::Clipboard clipboard(sfml.window);
186 const char* text = clipboard.getText();
187
188 if(text)
189 nk_textedit_paste(edit, text, nk_strlen(text));
190 (void)usr;
191 #endif
192 }
193
194 static void
nk_sfml_clipboard_copy(nk_handle usr,const char * text,int len)195 nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
196 {
197 #if 0
198 char* str = 0;
199 (void)usr;
200 if(!len) return;
201 str = (char*)malloc((size_t)len+1);
202 if(!str) return;
203 memcpy(str, text, (size_t)len);
204 str[len] = '\0';
205
206 /* Not Implemented in SFML */
207 sf::Clipboard clipboard(sfml.window);
208 clipboard.setText(str);
209 free(str);
210 #endif
211 }
212
213 NK_API struct nk_context*
nk_sfml_init(sf::Window * window)214 nk_sfml_init(sf::Window* window)
215 {
216 sfml.window = window;
217 nk_init_default(&sfml.ctx, 0);
218 sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
219 sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
220 sfml.ctx.clip.userdata = nk_handle_ptr(0);
221 nk_buffer_init_default(&sfml.ogl.cmds);
222 return &sfml.ctx;
223 }
224
225 NK_API void
nk_sfml_font_stash_begin(struct nk_font_atlas ** atlas)226 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
227 {
228 nk_font_atlas_init_default(&sfml.atlas);
229 nk_font_atlas_begin(&sfml.atlas);
230 *atlas = &sfml.atlas;
231 }
232
233 NK_API void
nk_sfml_font_stash_end()234 nk_sfml_font_stash_end()
235 {
236 int w, h;
237 const void* img;
238 img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
239 nk_sfml_device_upload_atlas(img, w, h);
240 nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
241 if(sfml.atlas.default_font)
242 nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
243 }
244
245 NK_API int
nk_sfml_handle_event(sf::Event * evt)246 nk_sfml_handle_event(sf::Event* evt)
247 {
248 struct nk_context* ctx = &sfml.ctx;
249 /* optional grabbing behavior */
250 if(ctx->input.mouse.grab)
251 ctx->input.mouse.grab = 0;
252 else if(ctx->input.mouse.ungrab) {
253 int x = (int)ctx->input.mouse.prev.x;
254 int y = (int)ctx->input.mouse.prev.y;
255 sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
256 ctx->input.mouse.ungrab = 0;
257 }
258 if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
259 {
260 int down = evt->type == sf::Event::KeyPressed;
261 sf::Keyboard::Key key = evt->key.code;
262 if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
263 nk_input_key(ctx, NK_KEY_SHIFT, down);
264 else if(key == sf::Keyboard::Delete)
265 nk_input_key(ctx, NK_KEY_DEL, down);
266 else if(key == sf::Keyboard::Return)
267 nk_input_key(ctx, NK_KEY_ENTER, down);
268 else if(key == sf::Keyboard::Tab)
269 nk_input_key(ctx, NK_KEY_TAB, down);
270 else if(key == sf::Keyboard::BackSpace)
271 nk_input_key(ctx, NK_KEY_BACKSPACE, down);
272 else if(key == sf::Keyboard::Home) {
273 nk_input_key(ctx, NK_KEY_TEXT_START, down);
274 nk_input_key(ctx, NK_KEY_SCROLL_START, down);
275 } else if(key == sf::Keyboard::End) {
276 nk_input_key(ctx, NK_KEY_TEXT_END, down);
277 nk_input_key(ctx, NK_KEY_SCROLL_END, down);
278 } else if(key == sf::Keyboard::PageDown)
279 nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
280 else if(key == sf::Keyboard::PageUp)
281 nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
282 else if(key == sf::Keyboard::Z)
283 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
284 else if(key == sf::Keyboard::R)
285 nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
286 else if(key == sf::Keyboard::C)
287 nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
288 else if(key == sf::Keyboard::V)
289 nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
290 else if(key == sf::Keyboard::X)
291 nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
292 else if(key == sf::Keyboard::B)
293 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
294 else if(key == sf::Keyboard::E)
295 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
296 else if(key == sf::Keyboard::Up)
297 nk_input_key(ctx, NK_KEY_UP, down);
298 else if(key == sf::Keyboard::Down)
299 nk_input_key(ctx, NK_KEY_DOWN, down);
300 else if(key == sf::Keyboard::Left) {
301 if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
302 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
303 else nk_input_key(ctx, NK_KEY_LEFT, down);
304 } else if(key == sf::Keyboard::Right) {
305 if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
306 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
307 else nk_input_key(ctx, NK_KEY_RIGHT, down);
308 } else return 0;
309 return 1;
310 } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
311 int down = evt->type == sf::Event::MouseButtonPressed;
312 const int x = evt->mouseButton.x, y = evt->mouseButton.y;
313 if(evt->mouseButton.button == sf::Mouse::Left)
314 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
315 if(evt->mouseButton.button == sf::Mouse::Middle)
316 nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
317 if(evt->mouseButton.button == sf::Mouse::Right)
318 nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
319 else return 0;
320 return 1;
321 } else if(evt->type == sf::Event::MouseMoved) {
322 nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
323 return 1;
324 } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
325 int down = evt->type == sf::Event::TouchBegan;
326 const int x = evt->touch.x, y = evt->touch.y;
327 ctx->input.mouse.pos.x = x;
328 ctx->input.mouse.pos.y = y;
329 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
330 return 1;
331 } else if(evt->type == sf::Event::TouchMoved) {
332 if(ctx->input.mouse.grabbed) {
333 int x = (int)ctx->input.mouse.prev.x;
334 int y = (int)ctx->input.mouse.prev.y;
335 nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
336 } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
337 return 1;
338 } else if(evt->type == sf::Event::TextEntered) {
339 nk_input_unicode(ctx, evt->text.unicode);
340 return 1;
341 } else if(evt->type == sf::Event::MouseWheelScrolled) {
342 nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
343 return 1;
344 }
345 return 0;
346 }
347
348 NK_API
nk_sfml_shutdown(void)349 void nk_sfml_shutdown(void)
350 {
351 struct nk_sfml_device* dev = &sfml.ogl;
352 nk_font_atlas_clear(&sfml.atlas);
353 nk_free(&sfml.ctx);
354 glDeleteTextures(1, &dev->font_tex);
355 nk_buffer_free(&dev->cmds);
356 memset(&sfml, 0, sizeof(sfml));
357 }
358
359 #endif
360