From cab14194133f8cd613c4a9ef352ef0e7b624a54b Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Mon, 27 Jul 2026 22:16:42 -0400 Subject: [PATCH 1/2] Fix image handle.ptr and empty region --- include/raylib-nuklear.h | 25 ++++++++++++++++++++++ test/raylib-nuklear-test.c | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/include/raylib-nuklear.h b/include/raylib-nuklear.h index 71400c5..efd1ab4 100644 --- a/include/raylib-nuklear.h +++ b/include/raylib-nuklear.h @@ -544,6 +544,19 @@ ColorToNuklearColorF(Color color) static struct Texture NuklearImageToTexture(struct nk_image img) { + // nk_handle is a union, so there is no flag telling whether the image was + // built from a texture id (nk_image_id(), TextureToNuklearImage()) or from + // a Texture pointer (nk_image_ptr(&texture)). Texture ids are small + // sequential OpenGL texture names, while pointers are addresses far beyond + // that range, so any handle value above RAYLIB_NUKLEAR_MAX_TEXTURE_ID is + // treated as a Texture pointer. + #ifndef RAYLIB_NUKLEAR_MAX_TEXTURE_ID + #define RAYLIB_NUKLEAR_MAX_TEXTURE_ID 0x100000 + #endif + if ((nk_ptr)img.handle.ptr > (nk_ptr)RAYLIB_NUKLEAR_MAX_TEXTURE_ID) { + return *(Texture*)img.handle.ptr; + } + Texture texture = {0}; texture.id = (unsigned int)img.handle.id; texture.width = (int)img.w; @@ -867,6 +880,18 @@ DrawNuklear(struct nk_context * ctx) const struct nk_command_image *i = (const struct nk_command_image *)cmd; Texture texture = NuklearImageToTexture(i->img); Rectangle source = CLITERAL(Rectangle) {(float)i->img.region[0], (float)i->img.region[1], (float)i->img.region[2], (float)i->img.region[3]}; + if (source.width <= 0 || source.height <= 0) { + // Images from nk_image_id(), nk_image_ptr() or nk_image_handle() have an empty region; use the full texture instead. + source.width = (i->img.w > 0) ? (float)i->img.w : (float)texture.width; + source.height = (i->img.h > 0) ? (float)i->img.h : (float)texture.height; + if (source.width <= 0 || source.height <= 0) { + // The texture size is unknown (nk_image_id() only carries the id), so map the whole texture onto the destination. + texture.width = 1; + texture.height = 1; + source.width = 1; + source.height = 1; + } + } Rectangle dest = CLITERAL(Rectangle) {(float)i->x * scale, (float)i->y * scale, (float)i->w * scale, (float)i->h * scale}; Vector2 origin = CLITERAL(Vector2) {0, 0}; Color tint = NuklearColorToColor(i->col); diff --git a/test/raylib-nuklear-test.c b/test/raylib-nuklear-test.c index e439be9..771cdc8 100644 --- a/test/raylib-nuklear-test.c +++ b/test/raylib-nuklear-test.c @@ -234,6 +234,49 @@ int main(int argc, char *argv[]) { UnloadNuklear(ctx); } + // NK_COMMAND_IMAGE: images from nk_image_id() and nk_image_ptr() must render (#130). + { + ctx = InitNuklear(10); + Assert(ctx); + + Texture imageTexture = LoadTexture("resources/test-image.png"); + AssertTexture(imageTexture); + + // Neither constructor fills in the size or region of the image. + struct nk_image imageFromId = nk_image_id((int)imageTexture.id); + struct nk_image imageFromPtr = nk_image_ptr(&imageTexture); + + UpdateNuklear(ctx); + + struct nk_rect idBounds = nk_rect(0, 0, 0, 0); + struct nk_rect ptrBounds = nk_rect(0, 0, 0, 0); + if (nk_begin(ctx, "ImageTest", nk_rect(0, 0, 200, 100), NK_WINDOW_NO_SCROLLBAR)) { + nk_layout_row_static(ctx, 64, 64, 2); + idBounds = nk_widget_bounds(ctx); + nk_image(ctx, imageFromId); + ptrBounds = nk_widget_bounds(ctx); + nk_image(ctx, imageFromPtr); + } + nk_end(ctx); + + BeginDrawing(); + ClearBackground(RED); + DrawNuklear(ctx); + EndDrawing(); + + // The test image is white in the middle, so both widgets must show it. + Image screen = LoadImageFromScreen(); + Color idColor = GetImageColor(screen, (int)(idBounds.x + idBounds.w / 2), (int)(idBounds.y + idBounds.h / 2)); + Color ptrColor = GetImageColor(screen, (int)(ptrBounds.x + ptrBounds.w / 2), (int)(ptrBounds.y + ptrBounds.h / 2)); + Color white = WHITE; + AssertColorSame(idColor, white, "nk_image_id() image did not render"); + AssertColorSame(ptrColor, white, "nk_image_ptr() image did not render"); + UnloadImage(screen); + + UnloadTexture(imageTexture); + UnloadNuklear(ctx); + } + // RAYLIB_NUKLEAR_VERSION macros Assert(RAYLIB_NUKLEAR_VERSION_MAJOR >= 1); Assert(RAYLIB_NUKLEAR_VERSION_MINOR >= 0); From 5d0c2205c0cf098058525eb2aef1b65a57ba556e Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Mon, 27 Jul 2026 22:32:16 -0400 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Rob Loach --- include/raylib-nuklear.h | 13 ------------ test/raylib-nuklear-test.c | 43 -------------------------------------- 2 files changed, 56 deletions(-) diff --git a/include/raylib-nuklear.h b/include/raylib-nuklear.h index efd1ab4..830849f 100644 --- a/include/raylib-nuklear.h +++ b/include/raylib-nuklear.h @@ -544,19 +544,6 @@ ColorToNuklearColorF(Color color) static struct Texture NuklearImageToTexture(struct nk_image img) { - // nk_handle is a union, so there is no flag telling whether the image was - // built from a texture id (nk_image_id(), TextureToNuklearImage()) or from - // a Texture pointer (nk_image_ptr(&texture)). Texture ids are small - // sequential OpenGL texture names, while pointers are addresses far beyond - // that range, so any handle value above RAYLIB_NUKLEAR_MAX_TEXTURE_ID is - // treated as a Texture pointer. - #ifndef RAYLIB_NUKLEAR_MAX_TEXTURE_ID - #define RAYLIB_NUKLEAR_MAX_TEXTURE_ID 0x100000 - #endif - if ((nk_ptr)img.handle.ptr > (nk_ptr)RAYLIB_NUKLEAR_MAX_TEXTURE_ID) { - return *(Texture*)img.handle.ptr; - } - Texture texture = {0}; texture.id = (unsigned int)img.handle.id; texture.width = (int)img.w; diff --git a/test/raylib-nuklear-test.c b/test/raylib-nuklear-test.c index 771cdc8..e439be9 100644 --- a/test/raylib-nuklear-test.c +++ b/test/raylib-nuklear-test.c @@ -234,49 +234,6 @@ int main(int argc, char *argv[]) { UnloadNuklear(ctx); } - // NK_COMMAND_IMAGE: images from nk_image_id() and nk_image_ptr() must render (#130). - { - ctx = InitNuklear(10); - Assert(ctx); - - Texture imageTexture = LoadTexture("resources/test-image.png"); - AssertTexture(imageTexture); - - // Neither constructor fills in the size or region of the image. - struct nk_image imageFromId = nk_image_id((int)imageTexture.id); - struct nk_image imageFromPtr = nk_image_ptr(&imageTexture); - - UpdateNuklear(ctx); - - struct nk_rect idBounds = nk_rect(0, 0, 0, 0); - struct nk_rect ptrBounds = nk_rect(0, 0, 0, 0); - if (nk_begin(ctx, "ImageTest", nk_rect(0, 0, 200, 100), NK_WINDOW_NO_SCROLLBAR)) { - nk_layout_row_static(ctx, 64, 64, 2); - idBounds = nk_widget_bounds(ctx); - nk_image(ctx, imageFromId); - ptrBounds = nk_widget_bounds(ctx); - nk_image(ctx, imageFromPtr); - } - nk_end(ctx); - - BeginDrawing(); - ClearBackground(RED); - DrawNuklear(ctx); - EndDrawing(); - - // The test image is white in the middle, so both widgets must show it. - Image screen = LoadImageFromScreen(); - Color idColor = GetImageColor(screen, (int)(idBounds.x + idBounds.w / 2), (int)(idBounds.y + idBounds.h / 2)); - Color ptrColor = GetImageColor(screen, (int)(ptrBounds.x + ptrBounds.w / 2), (int)(ptrBounds.y + ptrBounds.h / 2)); - Color white = WHITE; - AssertColorSame(idColor, white, "nk_image_id() image did not render"); - AssertColorSame(ptrColor, white, "nk_image_ptr() image did not render"); - UnloadImage(screen); - - UnloadTexture(imageTexture); - UnloadNuklear(ctx); - } - // RAYLIB_NUKLEAR_VERSION macros Assert(RAYLIB_NUKLEAR_VERSION_MAJOR >= 1); Assert(RAYLIB_NUKLEAR_VERSION_MINOR >= 0);