Immediate-Mode-UI / Nuklear

A single-header ANSI C immediate mode cross-platform GUI library
https://immediate-mode-ui.github.io/Nuklear/
Other
9.37k stars 571 forks source link

Image created in memory buffer triggers "if this triggers you forgot to add a font" #29

Closed crazyBaboon closed 4 years ago

crazyBaboon commented 4 years ago

I am trying to modify a function called icon_load() that currently is responsible for loading a .png image into memory, into a function that simply loads an image buffer that is created in heap memory.

Here is the original source code for it, defined in example/extended.c:

static struct nk_image
icon_load(const char *filename)
{
    int x,y,n;
    GLuint tex;
    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
    if (!data) die("[SDL]: failed to load image: %s", filename);

    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);
    stbi_image_free(data);
    return nk_image_id((int)tex);
}

Now, here is what I did to change icon_load() so that it loads image buffers instead of .png files: Instead of generating an image buffer from a .png file, I generated a 4 x 4 texel GL_RGBA texture on heap memory. I basically replaced stbi_load() (which returns a pointer to stbi_uc just a typedef for unsigned char) by malloc() (which returns a void pointer but it is cast to unsigned char). I have also replaced stbi_image_free() by free()):

static struct nk_image
icon_load(const char *filename)
{
    GLuint tex;

    unsigned char *data = (unsigned char*)malloc(64 * sizeof(char));
    static int messi = 1;    

    for (int i = 0; i < 64; i += 4)
    {   
        data[i + 0] = 4 * i;
        data[i + 1] = 0;
        data[i + 2] = 0;
        data[i + 3] = 0;
        printf("data[%d] = %d\n", i, data[i]);
    }   

    printf("Messi is %d\n", messi);
    messi++; 

    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);
    free(data);

    return nk_image_id((int)tex);
}

The output:

data[54] = 127
data[55] = 255
data[56] = 255Image created in memory triggers "if this triggers you forgot to add a font" 
data[57] = 127
data[58] = 255
data[59] = 127
data[60] = 255
data[61] = 127
data[62] = 255
data[63] = 127
Messi is 32
Segmentation fault (core dumped)

Looking at the output I assume that malloc() was successful.

The fact that Messi is now 32, indicates that icon_load() was successfully called 31 times for each of the icons/images in lines 821 - 829 , before any rendering was actually done.

Using good old printf() debugging I realised the crash occurs inside function nk_begin_titled() (located inside function basic_demo()):

NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font");

How can this be fixed? How can I load images from memory buffer rather than a .png file?

PS: I have opened an issue on a now archived instance of nuklear, and I did get an answer from @revolucas, where he suggests the font has not been initialised. But it was, as NK_INCLUDE_DEFAULT_FONT is defined in the begining of the extended.c file and nk_style_set_font(ctx, &media->font_20->handle); is called just before nk_begin_titled().

crazyBaboon commented 4 years ago

I found out the image is successfully displayed if i use the following function:

static struct nk_image
icon_load(const char *filename)
{
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    unsigned char* data = malloc(4 * 8 * 8 * sizeof(char));

    /* define image data: 4 RGBA channels, with 8 x 8 texels: */
    for (int i = 0; i < 4 * 8 * 8; i += 4)
    {
        data[i + 0] = (int)(4 * i) % 256;
        data[i + 1] = (int)(4 * i) % 256;
        data[i + 2] = (int)(4 * i) % 256;
        data[i + 3] = (int)(4 * i) % 256;
    }
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    if (data == NULL) printf("data is NULL!\n");

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);

    free(data);

    return nk_image_id((int)tex);
}

closed as solved :)