39 #include <SDL3/SDL_opengl.h> 
   45 NK_API 
void                 nk_sdl_render(
enum nk_anti_aliasing , 
int max_vertex_buffer, 
int max_element_buffer);
 
   53 #define GL_CALL_RET(x) ({ \ 
   55     GLenum __err = glGetError(); \ 
   56     if(__err != GL_NO_ERROR) \ 
   57         fprintf(stderr, "GL error 0x%X at %s:%d in %s\n", __err, __FILE__, __LINE__, __func__); \
 
   61 #define GL_CALL(x) do { \ 
   63     GLenum err = glGetError(); \ 
   64     if (err != GL_NO_ERROR) { \ 
   65         fprintf(stderr, "[GL ERROR] %s:%d %s -> 0x%X\n", __FILE__, __LINE__, #x, err); \
 
   76 #ifdef NK_SDL3_GL3_IMPLEMENTATION 
   82 struct nk_sdl_device {
 
   83     struct nk_buffer cmds;
 
   84     struct nk_draw_null_texture tex_null;
 
   97 struct nk_sdl_vertex {
 
  103 static struct nk_sdl {
 
  105     struct nk_sdl_device ogl;
 
  106     struct nk_context ctx;
 
  107     struct nk_font_atlas atlas;
 
  108     Uint64 time_of_last_frame;
 
  111 #if defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_EMSCRIPTEN) 
  112 #define SHADER_HEADER "#version 300 es\nprecision mediump float;\n" 
  114 #define SHADER_HEADER "#version 330 core\n" 
  122     static const GLchar *vertex_shader =
 
  124         "uniform mat4 ProjMtx;\n" 
  125         "in vec2 Position;\n" 
  126         "in vec2 TexCoord;\n" 
  128         "out vec2 Frag_UV;\n" 
  129         "out vec4 Frag_Color;\n" 
  131         "   Frag_UV = TexCoord;\n" 
  132         "   Frag_Color = Color;\n" 
  133         "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" 
  135     static const GLchar *fragment_shader =
 
  137         "uniform sampler2D Texture;\n" 
  139         "in vec4 Frag_Color;\n" 
  140         "out vec4 Out_Color;\n" 
  142         "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" 
  145     struct nk_sdl_device *dev = &sdl.ogl;
 
  146     nk_buffer_init_default(&dev->cmds);
 
  147     dev->prog = glCreateProgram();
 
  148     dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
 
  149     dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
 
  150     glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
 
  151     glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
 
  152     glCompileShader(dev->vert_shdr);
 
  153     glCompileShader(dev->frag_shdr);
 
  154     glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
 
  155     assert(status == GL_TRUE);
 
  156     glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
 
  157     assert(status == GL_TRUE);
 
  158     glAttachShader(dev->prog, dev->vert_shdr);
 
  159     glAttachShader(dev->prog, dev->frag_shdr);
 
  160     glLinkProgram(dev->prog);
 
  161     glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
 
  162     assert(status == GL_TRUE);
 
  164     dev->uniform_tex = glGetUniformLocation(dev->prog, 
"Texture");
 
  165     dev->uniform_proj = glGetUniformLocation(dev->prog, 
"ProjMtx");
 
  166     dev->attrib_pos = glGetAttribLocation(dev->prog, 
"Position");
 
  167     dev->attrib_uv = glGetAttribLocation(dev->prog, 
"TexCoord");
 
  168     dev->attrib_col = glGetAttribLocation(dev->prog, 
"Color");
 
  172         GLsizei vs = 
sizeof(
struct nk_sdl_vertex);
 
  173         size_t vp = offsetof(
struct nk_sdl_vertex, position);
 
  174         size_t vt = offsetof(
struct nk_sdl_vertex, uv);
 
  175         size_t vc = offsetof(
struct nk_sdl_vertex, col);
 
  177         glGenBuffers(1, &dev->vbo);
 
  178         glGenBuffers(1, &dev->ebo);
 
  179         glGenVertexArrays(1, &dev->vao);
 
  181         glBindVertexArray(dev->vao);
 
  182         glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
 
  183         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
 
  185         glEnableVertexAttribArray((GLuint)dev->attrib_pos);
 
  186         glEnableVertexAttribArray((GLuint)dev->attrib_uv);
 
  187         glEnableVertexAttribArray((GLuint)dev->attrib_col);
 
  189         glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (
void*)vp);
 
  190         glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (
void*)vt);
 
  191         glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (
void*)vc);
 
  194     glBindTexture(GL_TEXTURE_2D, 0);
 
  195     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
  196     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
  197     glBindVertexArray(0);
 
  201 nk_sdl_device_upload_atlas(
const void *image, 
int width, 
int height)
 
  203     struct nk_sdl_device *dev = &sdl.ogl;
 
  204     glGenTextures(1, &dev->font_tex);
 
  205     glBindTexture(GL_TEXTURE_2D, dev->font_tex);
 
  206     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
  207     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
  208     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
 
  209                 GL_RGBA, GL_UNSIGNED_BYTE, image);
 
  215     struct nk_sdl_device *dev = &sdl.ogl;
 
  216     glDetachShader(dev->prog, dev->vert_shdr);
 
  217     glDetachShader(dev->prog, dev->frag_shdr);
 
  218     glDeleteShader(dev->vert_shdr);
 
  219     glDeleteShader(dev->frag_shdr);
 
  220     glDeleteProgram(dev->prog);
 
  221     glDeleteTextures(1, &dev->font_tex);
 
  222     glDeleteBuffers(1, &dev->vbo);
 
  223     glDeleteBuffers(1, &dev->ebo);
 
  224     nk_buffer_free(&dev->cmds);
 
  228 nk_sdl_render(
enum nk_anti_aliasing AA, 
int max_vertex_buffer, 
int max_element_buffer)
 
  230     struct nk_sdl_device *dev = &sdl.ogl;
 
  232     int display_width, display_height;
 
  233     struct nk_vec2 scale;
 
  234     GLfloat ortho[4][4] = {
 
  235         {  2.0f,  0.0f,  0.0f, 0.0f },
 
  236         {  0.0f, -2.0f,  0.0f, 0.0f },
 
  237         {  0.0f,  0.0f, -1.0f, 0.0f },
 
  238         { -1.0f,  1.0f,  0.0f, 1.0f },
 
  241     Uint64 now = SDL_GetTicks();
 
  242     sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;
 
  243     sdl.time_of_last_frame = now;
 
  245     SDL_GetWindowSize(sdl.win, &width, &height);
 
  246     SDL_GetWindowSizeInPixels(sdl.win, &display_width, &display_height);
 
  247     ortho[0][0] /= (GLfloat)width;
 
  248     ortho[1][1] /= (GLfloat)height;
 
  250     scale.x = (float)display_width / (
float)width;
 
  251     scale.y = (float)display_height / (
float)height;
 
  253     glViewport(0, 0, display_width, display_height);
 
  255     glBlendEquation(GL_FUNC_ADD);
 
  256     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
  257     glDisable(GL_CULL_FACE);
 
  258     glDisable(GL_DEPTH_TEST);
 
  259     glEnable(GL_SCISSOR_TEST);
 
  260     glActiveTexture(GL_TEXTURE0);
 
  262     glUseProgram(dev->prog);
 
  263     glUniform1i(dev->uniform_tex, 0);
 
  264     glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
 
  267         const struct nk_draw_command *cmd;
 
  268         void *vertices, *elements;
 
  269         const nk_draw_index *offset = NULL;
 
  270         struct nk_buffer vbuf, ebuf;
 
  272         glBindVertexArray(dev->vao);
 
  273         glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
 
  274         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
 
  276         glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
 
  277         glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
 
  279         vertices = malloc(max_vertex_buffer);
 
  280         elements = malloc(max_element_buffer);
 
  283             struct nk_convert_config config;
 
  284             static const struct nk_draw_vertex_layout_element vertex_layout[] = {
 
  285                 {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(
struct nk_sdl_vertex, position)},
 
  286                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(
struct nk_sdl_vertex, uv)},
 
  287                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(
struct nk_sdl_vertex, col)},
 
  288                 {NK_VERTEX_LAYOUT_END}
 
  290             memset(&config, 0, 
sizeof(config));
 
  291             config.vertex_layout = vertex_layout;
 
  292             config.vertex_size = 
sizeof(
struct nk_sdl_vertex);
 
  293             config.vertex_alignment = NK_ALIGNOF(
struct nk_sdl_vertex);
 
  294             config.tex_null = dev->tex_null;
 
  295             config.circle_segment_count = 22;
 
  296             config.curve_segment_count = 22;
 
  297             config.arc_segment_count = 22;
 
  298             config.global_alpha = 1.0f;
 
  299             config.shape_AA = AA;
 
  302             nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
 
  303             nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
 
  304             nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
 
  310         glBufferSubData(GL_ARRAY_BUFFER, 0, max_vertex_buffer, vertices);
 
  311         glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, max_element_buffer, elements);
 
  317         nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
 
  318             if (!cmd->elem_count) 
continue;
 
  319             glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
 
  321                 (GLint)(cmd->clip_rect.x * scale.x),
 
  322                 (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
 
  323                 (GLint)(cmd->clip_rect.w * scale.x),
 
  324                 (GLint)(cmd->clip_rect.h * scale.y)
 
  326             glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
 
  327             offset += cmd->elem_count;
 
  331         nk_buffer_clear(&dev->cmds);
 
  335     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
  336     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
  337     glBindVertexArray(0);
 
  339     glDisable(GL_SCISSOR_TEST);
 
  343 nk_sdl_clipboard_paste(nk_handle usr, 
struct nk_text_edit *edit)
 
  345     const char *text = SDL_GetClipboardText();
 
  347         nk_textedit_paste(edit, text, nk_strlen(text));
 
  348         SDL_free((
void *)text);
 
  354 nk_sdl_clipboard_copy(nk_handle usr, 
const char *text, 
int len)
 
  359     str = (
char*)malloc((
size_t)len+1);
 
  361     memcpy(str, text, (
size_t)len);
 
  363     SDL_SetClipboardText(str);
 
  367 NK_API 
struct nk_context*
 
  371     nk_init_default(&sdl.ctx, 0);
 
  372     sdl.ctx.clip.copy = nk_sdl_clipboard_copy;
 
  373     sdl.ctx.clip.paste = nk_sdl_clipboard_paste;
 
  374     sdl.ctx.clip.userdata = nk_handle_ptr(0);
 
  376     sdl.time_of_last_frame = SDL_GetTicks();
 
  383     nk_font_atlas_init_default(&sdl.atlas);
 
  384     nk_font_atlas_begin(&sdl.atlas);
 
  391     const void *image; 
int w, h;
 
  392     image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
 
  393     nk_sdl_device_upload_atlas(image, w, h);
 
  394     nk_font_atlas_end(&sdl.atlas, nk_handle_id((
int)sdl.ogl.font_tex), &sdl.ogl.tex_null);
 
  395     if (sdl.atlas.default_font)
 
  396         nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
 
  403     struct nk_context *ctx = &sdl.ctx;
 
  404     if (ctx->input.mouse.grab) {
 
  405         SDL_SetWindowRelativeMouseMode(sdl.win, 
true);
 
  406     } 
else if (ctx->input.mouse.ungrab) {
 
  408         SDL_SetWindowRelativeMouseMode(sdl.win, 
false);
 
  409         SDL_WarpMouseInWindow(sdl.win, (
int)ctx->input.mouse.prev.x, (
int)ctx->input.mouse.prev.y);
 
  410     } 
else if (ctx->input.mouse.grabbed) {
 
  411         ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
 
  412         ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
 
  419     struct nk_context *ctx = &sdl.ctx;
 
  420     int ctrl_down = SDL_GetModState() & (SDL_KMOD_LCTRL | SDL_KMOD_RCTRL);
 
  424         case SDL_EVENT_KEY_UP: 
 
  425         case SDL_EVENT_KEY_DOWN:
 
  427                 int down = evt->type == SDL_EVENT_KEY_DOWN;
 
  431                     case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); 
break;
 
  432                     case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); 
break;
 
  435                     case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); 
break;
 
  437                     case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); 
break;
 
  438                     case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); 
break;
 
  439                     case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);
 
  440                                          nk_input_key(ctx, NK_KEY_SCROLL_START, down); 
break;
 
  441                     case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);
 
  442                                          nk_input_key(ctx, NK_KEY_SCROLL_END, down); 
break;
 
  443                     case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); 
break;
 
  444                     case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); 
break;
 
  445                     case SDLK_Z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); 
break;
 
  446                     case SDLK_R:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); 
break;
 
  447                     case SDLK_C:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); 
break;
 
  448                     case SDLK_V:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); 
break;
 
  449                     case SDLK_X:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); 
break;
 
  450                     case SDLK_B:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); 
break;
 
  451                     case SDLK_E:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); 
break;
 
  452                     case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); 
break;
 
  453                     case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); 
break;
 
  456                             nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);
 
  460                             nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
 
  461                         else nk_input_key(ctx, NK_KEY_LEFT, down);
 
  465                             nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
 
  466                         else nk_input_key(ctx, NK_KEY_RIGHT, down);
 
  472         case SDL_EVENT_MOUSE_BUTTON_UP: 
 
  473         case SDL_EVENT_MOUSE_BUTTON_DOWN:
 
  475                 int down = evt->type == SDL_EVENT_MOUSE_BUTTON_DOWN;
 
  476                 const int x = evt->button.x, y = evt->button.y;
 
  477                 switch(evt->button.button)
 
  479                     case SDL_BUTTON_LEFT:
 
  480                         if (evt->button.clicks > 1)
 
  481                             nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
 
  482                         nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); 
break;
 
  483                     case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); 
break;
 
  484                     case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); 
break;
 
  489         case SDL_EVENT_MOUSE_MOTION:
 
  490             if (ctx->input.mouse.grabbed) {
 
  491                 int x = (int)ctx->input.mouse.prev.x, y = (
int)ctx->input.mouse.prev.y;
 
  492                 nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
 
  494             else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
 
  497         case SDL_EVENT_TEXT_INPUT:
 
  503             const char *text = evt->text.text;
 
  504             glyph_len = byte_len = nk_utf_decode(text, &unicode, 4);
 
  505             while (unicode != 
'\0' && glyph_len) {
 
  506                 nk_input_unicode(ctx, unicode);
 
  507                 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
 
  508                 byte_len += glyph_len;
 
  513         case SDL_EVENT_MOUSE_WHEEL:
 
  514             nk_input_scroll(ctx,nk_vec2(evt->wheel.x, evt->wheel.y));
 
  523     nk_font_atlas_clear(&sdl.atlas);
 
  526     memset(&sdl, 0, 
sizeof(sdl));
 
NK_API int nk_sdl_handle_event(SDL_Event *evt)
NK_API void nk_sdl_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer)
NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
NK_API void nk_sdl_handle_grab(void)
NK_API void nk_sdl_device_create(void)
NK_API struct nk_context * nk_sdl_init(SDL_Window *win)
NK_API void nk_sdl_shutdown(void)
NK_API void nk_sdl_device_destroy(void)
NK_API void nk_sdl_font_stash_end(void)
#define SHADER_HEADER
Definition: ogl_struct.cpp:7