-
Notifications
You must be signed in to change notification settings - Fork 648
Open
Description
Hello, I’ve found a bug in Nuklear related to nk_label_wrap (and other wrapped text widgets).
When rendering wrapped text, the last character of a line is incorrectly dropped due to an off-by-one logic issue in nk_text_clamp.
Expected behavior
All characters in the input string should be visible, with line breaks applied when the text exceeds the available width.
Actual behavior
The last character on each wrapped line is missing (see figure).

Minimal Reproducible Example
The following standalone code (C99 + GLFW3 + GLAD + Nuklear) demonstrates the issue:
Source code
//2025.09.10
//BUG: Last character of each wrapped line disappears (issue in nk_text_clamp)
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#include "nuklear/nuklear.h"
#include "nuklear/nuklear_glfw_gl3.h"
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024
typedef struct {
GLFWwindow* window;
struct nk_context* nk_ctx;
struct nk_glfw nk_glfw;
} app_state;
static void app_init_glfw_window(app_state* st, int w, int h) {
assert(glfwInit());
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
st->window = glfwCreateWindow(w, h, "Test App", NULL, NULL);
assert(st->window);
glfwSetWindowPos(st->window, 100, 100);
glfwMakeContextCurrent(st->window);
assert(gladLoadGL(glfwGetProcAddress));
}
static void app_nuklear_init(app_state* st) {
st->nk_ctx = nk_glfw3_init(&st->nk_glfw, st->window, NK_GLFW3_INSTALL_CALLBACKS);
struct nk_font_atlas* atlas;
nk_glfw3_font_stash_begin(&st->nk_glfw, &atlas);
nk_glfw3_font_stash_end(&st->nk_glfw);
}
static void app_init(app_state* st) {
app_init_glfw_window(st, 800, 600);
app_nuklear_init(st);
}
static inline int app_window_open(app_state* st) {
return !glfwWindowShouldClose(st->window);
}
static void app_ui_frame(app_state* st) {
struct nk_context* ctx = st->nk_ctx;
nk_glfw3_new_frame(&st->nk_glfw);
nk_begin(ctx, "ABC", nk_rect(10, 10, 100, 200), NK_WINDOW_NOT_INTERACTIVE | NK_WINDOW_NO_SCROLLBAR);
{
nk_layout_row_dynamic(ctx, 100, 1);
struct nk_rect r = nk_widget_bounds(ctx);
nk_fill_rect(&ctx->current->buffer, r, 0, nk_rgb(110,70,70));
nk_label_wrap(ctx, "0123456789_0123456789_0123456789_0123456789_0123456789_0123456789");
}
nk_end(ctx);
nk_glfw3_render(&st->nk_glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}
static void app_frame(app_state* st) {
glfwPollEvents();
int width, height;
glfwGetFramebufferSize(st->window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
app_ui_frame(st);
glfwSwapBuffers(st->window);
}
static void app_free(app_state* st) {
nk_glfw3_shutdown(&st->nk_glfw);
glfwDestroyWindow(st->window);
glfwTerminate();
}
int main(void) {
static app_state st = { 0 };
app_init(&st);
while (app_window_open(&st)) {
app_frame(&st);
}
app_free(&st);
return 0;
}Metadata
Metadata
Assignees
Labels
No labels