Mercurial > repos > blastem
comparison nuklear_ui/nuklear_sdl_gles2.h @ 1474:c5c022c7aa54 nuklear_ui
Initial work on Nuklear-based UI
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 21 Nov 2017 19:07:43 -0800 |
parents | |
children | b82a44729d7c |
comparison
equal
deleted
inserted
replaced
1473:152a60c6787e | 1474:c5c022c7aa54 |
---|---|
1 /* | |
2 * Nuklear - 1.40.8 - public domain | |
3 * no warrenty implied; use at your own risk. | |
4 * authored from 2015-2017 by Micha Mettke | |
5 * emscripten from 2016 by Chris Willcocks | |
6 * OpenGL ES 2.0 from 2017 by Dmitry Hrabrov a.k.a. DeXPeriX | |
7 */ | |
8 /* | |
9 * ============================================================== | |
10 * | |
11 * API | |
12 * | |
13 * =============================================================== | |
14 */ | |
15 #ifndef NK_SDL_GLES2_H_ | |
16 #define NK_SDL_GLES2_H_ | |
17 | |
18 #include <SDL2/SDL.h> | |
19 #include <SDL2/SDL_opengles2.h> | |
20 | |
21 | |
22 NK_API struct nk_context* nk_sdl_init(SDL_Window *win); | |
23 NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas); | |
24 NK_API void nk_sdl_font_stash_end(void); | |
25 NK_API int nk_sdl_handle_event(SDL_Event *evt); | |
26 NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer); | |
27 NK_API void nk_sdl_shutdown(void); | |
28 NK_API void nk_sdl_device_destroy(void); | |
29 NK_API void nk_sdl_device_create(void); | |
30 | |
31 #endif | |
32 | |
33 /* | |
34 * ============================================================== | |
35 * | |
36 * IMPLEMENTATION | |
37 * | |
38 * =============================================================== | |
39 */ | |
40 #ifdef NK_SDL_GLES2_IMPLEMENTATION | |
41 | |
42 #include <string.h> | |
43 | |
44 struct nk_sdl_device { | |
45 struct nk_buffer cmds; | |
46 struct nk_draw_null_texture null; | |
47 GLuint vbo, 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 GLsizei vs; | |
58 size_t vp, vt, vc; | |
59 }; | |
60 | |
61 struct nk_sdl_vertex { | |
62 GLfloat position[2]; | |
63 GLfloat uv[2]; | |
64 nk_byte col[4]; | |
65 }; | |
66 | |
67 static struct nk_sdl { | |
68 SDL_Window *win; | |
69 struct nk_sdl_device ogl; | |
70 struct nk_context ctx; | |
71 struct nk_font_atlas atlas; | |
72 } sdl; | |
73 | |
74 | |
75 #define NK_SHADER_VERSION "#version 100\n" | |
76 | |
77 | |
78 NK_API void | |
79 nk_sdl_device_create(void) | |
80 { | |
81 GLint status; | |
82 static const GLchar *vertex_shader = | |
83 NK_SHADER_VERSION | |
84 "uniform mat4 ProjMtx;\n" | |
85 "attribute vec2 Position;\n" | |
86 "attribute vec2 TexCoord;\n" | |
87 "attribute vec4 Color;\n" | |
88 "varying vec2 Frag_UV;\n" | |
89 "varying vec4 Frag_Color;\n" | |
90 "void main() {\n" | |
91 " Frag_UV = TexCoord;\n" | |
92 " Frag_Color = Color;\n" | |
93 " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" | |
94 "}\n"; | |
95 static const GLchar *fragment_shader = | |
96 NK_SHADER_VERSION | |
97 "precision mediump float;\n" | |
98 "uniform sampler2D Texture;\n" | |
99 "varying vec2 Frag_UV;\n" | |
100 "varying vec4 Frag_Color;\n" | |
101 "void main(){\n" | |
102 " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);\n" | |
103 "}\n"; | |
104 | |
105 struct nk_sdl_device *dev = &sdl.ogl; | |
106 | |
107 nk_buffer_init_default(&dev->cmds); | |
108 dev->prog = glCreateProgram(); | |
109 dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); | |
110 dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); | |
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 glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); | |
116 assert(status == GL_TRUE); | |
117 glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); | |
118 assert(status == GL_TRUE); | |
119 glAttachShader(dev->prog, dev->vert_shdr); | |
120 glAttachShader(dev->prog, dev->frag_shdr); | |
121 glLinkProgram(dev->prog); | |
122 glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); | |
123 assert(status == GL_TRUE); | |
124 | |
125 | |
126 dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); | |
127 dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); | |
128 dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); | |
129 dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); | |
130 dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); | |
131 { | |
132 dev->vs = sizeof(struct nk_sdl_vertex); | |
133 dev->vp = offsetof(struct nk_sdl_vertex, position); | |
134 dev->vt = offsetof(struct nk_sdl_vertex, uv); | |
135 dev->vc = offsetof(struct nk_sdl_vertex, col); | |
136 | |
137 /* Allocate buffers */ | |
138 glGenBuffers(1, &dev->vbo); | |
139 glGenBuffers(1, &dev->ebo); | |
140 } | |
141 glBindTexture(GL_TEXTURE_2D, 0); | |
142 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
143 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
144 } | |
145 | |
146 NK_INTERN void | |
147 nk_sdl_device_upload_atlas(const void *image, int width, int height) | |
148 { | |
149 struct nk_sdl_device *dev = &sdl.ogl; | |
150 glGenTextures(1, &dev->font_tex); | |
151 glBindTexture(GL_TEXTURE_2D, dev->font_tex); | |
152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
153 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
154 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, | |
155 GL_RGBA, GL_UNSIGNED_BYTE, image); | |
156 } | |
157 | |
158 NK_API void | |
159 nk_sdl_device_destroy(void) | |
160 { | |
161 struct nk_sdl_device *dev = &sdl.ogl; | |
162 glDetachShader(dev->prog, dev->vert_shdr); | |
163 glDetachShader(dev->prog, dev->frag_shdr); | |
164 glDeleteShader(dev->vert_shdr); | |
165 glDeleteShader(dev->frag_shdr); | |
166 glDeleteProgram(dev->prog); | |
167 glDeleteTextures(1, &dev->font_tex); | |
168 glDeleteBuffers(1, &dev->vbo); | |
169 glDeleteBuffers(1, &dev->ebo); | |
170 nk_buffer_free(&dev->cmds); | |
171 } | |
172 | |
173 NK_API void | |
174 nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) | |
175 { | |
176 struct nk_sdl_device *dev = &sdl.ogl; | |
177 int width, height; | |
178 int display_width, display_height; | |
179 struct nk_vec2 scale; | |
180 GLfloat ortho[4][4] = { | |
181 {2.0f, 0.0f, 0.0f, 0.0f}, | |
182 {0.0f,-2.0f, 0.0f, 0.0f}, | |
183 {0.0f, 0.0f,-1.0f, 0.0f}, | |
184 {-1.0f,1.0f, 0.0f, 1.0f}, | |
185 }; | |
186 SDL_GetWindowSize(sdl.win, &width, &height); | |
187 SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height); | |
188 ortho[0][0] /= (GLfloat)width; | |
189 ortho[1][1] /= (GLfloat)height; | |
190 | |
191 scale.x = (float)display_width/(float)width; | |
192 scale.y = (float)display_height/(float)height; | |
193 | |
194 /* setup global state */ | |
195 glViewport(0,0,display_width,display_height); | |
196 glEnable(GL_BLEND); | |
197 glBlendEquation(GL_FUNC_ADD); | |
198 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
199 glDisable(GL_CULL_FACE); | |
200 glDisable(GL_DEPTH_TEST); | |
201 glEnable(GL_SCISSOR_TEST); | |
202 glActiveTexture(GL_TEXTURE0); | |
203 | |
204 /* setup program */ | |
205 glUseProgram(dev->prog); | |
206 glUniform1i(dev->uniform_tex, 0); | |
207 glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); | |
208 { | |
209 /* convert from command queue into draw list and draw to screen */ | |
210 const struct nk_draw_command *cmd; | |
211 void *vertices, *elements; | |
212 const nk_draw_index *offset = NULL; | |
213 | |
214 /* Bind buffers */ | |
215 glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); | |
216 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); | |
217 | |
218 { | |
219 /* buffer setup */ | |
220 glEnableVertexAttribArray((GLuint)dev->attrib_pos); | |
221 glEnableVertexAttribArray((GLuint)dev->attrib_uv); | |
222 glEnableVertexAttribArray((GLuint)dev->attrib_col); | |
223 | |
224 glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vp); | |
225 glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vt); | |
226 glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, dev->vs, (void*)dev->vc); | |
227 } | |
228 | |
229 glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); | |
230 glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); | |
231 | |
232 /* load vertices/elements directly into vertex/element buffer */ | |
233 vertices = malloc((size_t)max_vertex_buffer); | |
234 elements = malloc((size_t)max_element_buffer); | |
235 { | |
236 /* fill convert configuration */ | |
237 struct nk_convert_config config; | |
238 static const struct nk_draw_vertex_layout_element vertex_layout[] = { | |
239 {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)}, | |
240 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)}, | |
241 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)}, | |
242 {NK_VERTEX_LAYOUT_END} | |
243 }; | |
244 NK_MEMSET(&config, 0, sizeof(config)); | |
245 config.vertex_layout = vertex_layout; | |
246 config.vertex_size = sizeof(struct nk_sdl_vertex); | |
247 config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex); | |
248 config.null = dev->null; | |
249 config.circle_segment_count = 22; | |
250 config.curve_segment_count = 22; | |
251 config.arc_segment_count = 22; | |
252 config.global_alpha = 1.0f; | |
253 config.shape_AA = AA; | |
254 config.line_AA = AA; | |
255 | |
256 /* setup buffers to load vertices and elements */ | |
257 {struct nk_buffer vbuf, ebuf; | |
258 nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer); | |
259 nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer); | |
260 nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);} | |
261 } | |
262 glBufferSubData(GL_ARRAY_BUFFER, 0, (size_t)max_vertex_buffer, vertices); | |
263 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, (size_t)max_element_buffer, elements); | |
264 free(vertices); | |
265 free(elements); | |
266 | |
267 /* iterate over and execute each draw command */ | |
268 nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) { | |
269 if (!cmd->elem_count) continue; | |
270 glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); | |
271 glScissor((GLint)(cmd->clip_rect.x * scale.x), | |
272 (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), | |
273 (GLint)(cmd->clip_rect.w * scale.x), | |
274 (GLint)(cmd->clip_rect.h * scale.y)); | |
275 glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); | |
276 offset += cmd->elem_count; | |
277 } | |
278 nk_clear(&sdl.ctx); | |
279 } | |
280 | |
281 glUseProgram(0); | |
282 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
283 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
284 | |
285 glDisable(GL_BLEND); | |
286 glDisable(GL_SCISSOR_TEST); | |
287 } | |
288 | |
289 static void | |
290 nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) | |
291 { | |
292 const char *text = SDL_GetClipboardText(); | |
293 if (text) nk_textedit_paste(edit, text, nk_strlen(text)); | |
294 (void)usr; | |
295 } | |
296 | |
297 static void | |
298 nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len) | |
299 { | |
300 char *str = 0; | |
301 (void)usr; | |
302 if (!len) return; | |
303 str = (char*)malloc((size_t)len+1); | |
304 if (!str) return; | |
305 memcpy(str, text, (size_t)len); | |
306 str[len] = '\0'; | |
307 SDL_SetClipboardText(str); | |
308 free(str); | |
309 } | |
310 | |
311 NK_API struct nk_context* | |
312 nk_sdl_init(SDL_Window *win) | |
313 { | |
314 sdl.win = win; | |
315 nk_init_default(&sdl.ctx, 0); | |
316 sdl.ctx.clip.copy = nk_sdl_clipbard_copy; | |
317 sdl.ctx.clip.paste = nk_sdl_clipbard_paste; | |
318 sdl.ctx.clip.userdata = nk_handle_ptr(0); | |
319 nk_sdl_device_create(); | |
320 return &sdl.ctx; | |
321 } | |
322 | |
323 NK_API void | |
324 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) | |
325 { | |
326 nk_font_atlas_init_default(&sdl.atlas); | |
327 nk_font_atlas_begin(&sdl.atlas); | |
328 *atlas = &sdl.atlas; | |
329 } | |
330 | |
331 NK_API void | |
332 nk_sdl_font_stash_end(void) | |
333 { | |
334 const void *image; int w, h; | |
335 image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); | |
336 nk_sdl_device_upload_atlas(image, w, h); | |
337 nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null); | |
338 if (sdl.atlas.default_font) | |
339 nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle); | |
340 | |
341 } | |
342 | |
343 NK_API int | |
344 nk_sdl_handle_event(SDL_Event *evt) | |
345 { | |
346 struct nk_context *ctx = &sdl.ctx; | |
347 if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) { | |
348 /* key events */ | |
349 int down = evt->type == SDL_KEYDOWN; | |
350 const Uint8* state = SDL_GetKeyboardState(0); | |
351 SDL_Keycode sym = evt->key.keysym.sym; | |
352 if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT) | |
353 nk_input_key(ctx, NK_KEY_SHIFT, down); | |
354 else if (sym == SDLK_DELETE) | |
355 nk_input_key(ctx, NK_KEY_DEL, down); | |
356 else if (sym == SDLK_RETURN) | |
357 nk_input_key(ctx, NK_KEY_ENTER, down); | |
358 else if (sym == SDLK_TAB) | |
359 nk_input_key(ctx, NK_KEY_TAB, down); | |
360 else if (sym == SDLK_BACKSPACE) | |
361 nk_input_key(ctx, NK_KEY_BACKSPACE, down); | |
362 else if (sym == SDLK_HOME) { | |
363 nk_input_key(ctx, NK_KEY_TEXT_START, down); | |
364 nk_input_key(ctx, NK_KEY_SCROLL_START, down); | |
365 } else if (sym == SDLK_END) { | |
366 nk_input_key(ctx, NK_KEY_TEXT_END, down); | |
367 nk_input_key(ctx, NK_KEY_SCROLL_END, down); | |
368 } else if (sym == SDLK_PAGEDOWN) { | |
369 nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); | |
370 } else if (sym == SDLK_PAGEUP) { | |
371 nk_input_key(ctx, NK_KEY_SCROLL_UP, down); | |
372 } else if (sym == SDLK_z) | |
373 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]); | |
374 else if (sym == SDLK_r) | |
375 nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]); | |
376 else if (sym == SDLK_c) | |
377 nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]); | |
378 else if (sym == SDLK_v) | |
379 nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]); | |
380 else if (sym == SDLK_x) | |
381 nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]); | |
382 else if (sym == SDLK_b) | |
383 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]); | |
384 else if (sym == SDLK_e) | |
385 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]); | |
386 else if (sym == SDLK_UP) | |
387 nk_input_key(ctx, NK_KEY_UP, down); | |
388 else if (sym == SDLK_DOWN) | |
389 nk_input_key(ctx, NK_KEY_DOWN, down); | |
390 else if (sym == SDLK_LEFT) { | |
391 if (state[SDL_SCANCODE_LCTRL]) | |
392 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); | |
393 else nk_input_key(ctx, NK_KEY_LEFT, down); | |
394 } else if (sym == SDLK_RIGHT) { | |
395 if (state[SDL_SCANCODE_LCTRL]) | |
396 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); | |
397 else nk_input_key(ctx, NK_KEY_RIGHT, down); | |
398 } else return 0; | |
399 return 1; | |
400 } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) { | |
401 /* mouse button */ | |
402 int down = evt->type == SDL_MOUSEBUTTONDOWN; | |
403 const int x = evt->button.x, y = evt->button.y; | |
404 if (evt->button.button == SDL_BUTTON_LEFT) { | |
405 if (evt->button.clicks > 1) | |
406 nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down); | |
407 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); | |
408 } else if (evt->button.button == SDL_BUTTON_MIDDLE) | |
409 nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); | |
410 else if (evt->button.button == SDL_BUTTON_RIGHT) | |
411 nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); | |
412 return 1; | |
413 } else if (evt->type == SDL_MOUSEMOTION) { | |
414 /* mouse motion */ | |
415 if (ctx->input.mouse.grabbed) { | |
416 int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y; | |
417 nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel); | |
418 } else nk_input_motion(ctx, evt->motion.x, evt->motion.y); | |
419 return 1; | |
420 } else if (evt->type == SDL_TEXTINPUT) { | |
421 /* text input */ | |
422 nk_glyph glyph; | |
423 memcpy(glyph, evt->text.text, NK_UTF_SIZE); | |
424 nk_input_glyph(ctx, glyph); | |
425 return 1; | |
426 } else if (evt->type == SDL_MOUSEWHEEL) { | |
427 /* mouse wheel */ | |
428 nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y)); | |
429 return 1; | |
430 } | |
431 return 0; | |
432 } | |
433 | |
434 NK_API | |
435 void nk_sdl_shutdown(void) | |
436 { | |
437 nk_font_atlas_clear(&sdl.atlas); | |
438 nk_free(&sdl.ctx); | |
439 nk_sdl_device_destroy(); | |
440 memset(&sdl, 0, sizeof(sdl)); | |
441 } | |
442 | |
443 #endif |