Nuklear OpenGL flicker issue

277 Views Asked by At

I have downloaded the demo program for Nucklear in LWJGL, i've managed to compile it and have it to succesfully work. Then i've tried to implement the same code into my game engine and nothing shows up, unless i disable glClear(GL_COLOR_BUFFER_BIT). At that point i can see the little Nuklear window flickering.

This is my Window class

package Engine.Renderer;

import Engine.Messages.AppMsg;
import Engine.IntApplication;
import Engine.Messages.Type;  
import Simulator.Application;
import org.lwjgl.nuklear.NkColorf;
import org.lwjgl.nuklear.NkMouse;
import org.lwjgl.opengl.*;
import org.lwjgl.system.Callback;
import org.lwjgl.system.MemoryStack;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.ARBDebugOutput.*;
import static org.lwjgl.opengl.ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;

public class Window
{
public Window(int width, int height, String title)
{
    m_Width = width;
    m_Height = height;
    m_Title = title;

    if(!glfwInit())
    {
        ///TODO: LOG
        Runtime.getRuntime().exit(1);
    }

    glfwDefaultWindowHints();
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, NULL, NULL);
    if(m_Window == NULL)
    {
        ///TODO: LOG
        Runtime.getRuntime().exit(1);
    }

    glfwMakeContextCurrent(m_Window);
    GLCapabilities caps = GL.createCapabilities();
    glfwShowWindow(m_Window);

    Callback debugProc = GLUtil.setupDebugMessageCallback();

    if (caps.OpenGL43) {
        GL43.glDebugMessageControl(GL43.GL_DEBUG_SOURCE_API, GL43.GL_DEBUG_TYPE_OTHER, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, (IntBuffer)null, false);
    } else if (caps.GL_KHR_debug) {
        KHRDebug.glDebugMessageControl(
                KHRDebug.GL_DEBUG_SOURCE_API,
                KHRDebug.GL_DEBUG_TYPE_OTHER,
                KHRDebug.GL_DEBUG_SEVERITY_NOTIFICATION,
                (IntBuffer)null,
                false
        );
    } else if (caps.GL_ARB_debug_output) {
        glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, GL_DEBUG_SEVERITY_LOW_ARB, (IntBuffer)null, false);
    }

    SetUpWindow();
    renderer = new GUIRenderer();
}

public void Draw()
{

}

public void processEvents()
{
    try (MemoryStack stack = stackPush()) {
        IntBuffer w = stack.mallocInt(1);
        IntBuffer h = stack.mallocInt(1);

        glfwGetWindowSize(m_Window, w, h);
        m_Width = w.get(0);
        m_Height = h.get(0);

        glfwGetFramebufferSize(m_Window, w, h);
        m_DisplayWidth = w.get(0);
        m_DisplayHeight = h.get(0);
    }

    nk_input_begin(NuklearContainer.ctx);
    glfwPollEvents();

    NkMouse mouse = NuklearContainer.ctx.input().mouse();
    if (mouse.grab()) {
        glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
    } else if (mouse.grabbed()) {
        float prevX = mouse.prev().x();
        float prevY = mouse.prev().y();
        glfwSetCursorPos(m_Window, prevX, prevY);
        mouse.pos().x(prevX);
        mouse.pos().y(prevY);
    } else if (mouse.ungrab()) {
        glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
    }

    nk_input_end(NuklearContainer.ctx);

    try (MemoryStack stack = stackPush()) {
        IntBuffer width  = stack.mallocInt(1);
        IntBuffer height = stack.mallocInt(1);

        glfwGetWindowSize(m_Window, width, height);
        glViewport(0, 0, width.get(0), height.get(0));

        NkColorf bg = NkColorf.create().r(0.10f).g(0.18f).b(0.24f).a(1.0f);
        glClearColor(bg.r(), bg.g(), bg.b(), bg.a());
    }
    //glClear(GL_COLOR_BUFFER_BIT);
    renderer.Render();
    glfwSwapBuffers(m_Window);
}

public void CleanUp()
{
    glfwFreeCallbacks(m_Window);
    glfwDestroyWindow(m_Window);
    glfwTerminate();
}

private void SetUpWindow()
{
    glfwSetKeyCallback(m_Window, (window, key, scancode, action, mods) ->
    {
        AppMsg msg = new AppMsg();
        msg.key = key;
        msg.scancode = scancode;
        msg.mods = mods;

        if(action == 0)
            msg.type = Type.KEYUP;
        if(action == 1)
            msg.type = Type.KEYDOWN;
        if(action == 2)
            msg.type = Type.KEYREPEAT;

        IntApplication.OnMsgProc(msg);
    });

    glfwSetMouseButtonCallback(m_Window, (window, button, action, mods) ->
    {
        AppMsg msg = new AppMsg();
        msg.button = button;
        msg.mods = mods;

        if(action == 0)
            msg.type = Type.MOUSEUP;
        if(action == 1)
            msg.type = Type.MOUSEDOWN;

        Application.OnMsgProc(msg);
    });

    glfwSetCursorPosCallback(m_Window, (window, xpos, ypos) ->
    {
        AppMsg msg = new AppMsg();
        msg.xpos = xpos;
        msg.ypos = ypos;
        msg.type = Type.MOUSEMOVE;

        Application.OnMsgProc(msg);
    });

    glfwSetWindowCloseCallback(m_Window, (window) ->
            IntApplication.OnClose());

    nk_init(NuklearContainer.ctx, NuklearContainer.ALLOCATOR, null);
    NuklearContainer.ctx.clip()
            .copy((handle, text, len) -> {
                if (len == 0) {
                    return;
                }

                try (MemoryStack stack = stackPush()) {
                    ByteBuffer str = stack.malloc(len + 1);
                    memCopy(text, memAddress(str), len);
                    str.put(len, (byte)0);

                    glfwSetClipboardString(m_Window, str);
                }
            })
            .paste((handle, edit) -> {
                long text = nglfwGetClipboardString(m_Window);
                if (text != NULL) {
                    nnk_textedit_paste(edit, text, nnk_strlen(text));
                }
            });
}

private long m_Window;
static int m_Width, m_Height;
static int m_DisplayWidth, m_DisplayHeight;
private String m_Title;
GUIRenderer renderer;
}

And here is my GUIRender class

package Engine.Renderer;

import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.GL20C.*;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import static org.lwjgl.stb.STBTruetype.*;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointHMetrics;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.system.MemoryUtil.memAddress;

import Engine.IOUtil;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Objects;

import org.lwjgl.nuklear.*;
import org.lwjgl.stb.STBTTAlignedQuad;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTTPackContext;
import org.lwjgl.stb.STBTTPackedchar;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.Platform;

public class GUIRenderer extends Renderer
{
public GUIRenderer()
{
    super();

    try
    {
        this.ttf = IOUtil.ioResourceToByteBuffer("C:/Windows/Fonts/Arial.ttf", 512 * 1024);
    } catch (IOException e)
    {
        throw new RuntimeException(e);
    }

    if (!m_Initialized)
        Initialize();

    try (MemoryStack stack = stackPush()) {
        NkRect rect = NkRect.mallocStack(stack);

        if (nk_begin(
                NuklearContainer.ctx,
                "Hello World",
                nk_rect(50, 50, 230, 250, rect),
                NK_WINDOW_BORDER | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_TITLE
        )) {
            nk_layout_row_static(NuklearContainer.ctx, 20, 80, 1);
            nk_label(NuklearContainer.ctx, "background:", NK_TEXT_LEFT);
            }
        }
        nk_end(NuklearContainer.ctx);
}

private void Initialize()
{
    String NK_SHADER_VERSION = Platform.get() == Platform.MACOSX ? "#version 150\n" : "#version 300 es\n";
    String vertex_shader =
            NK_SHADER_VERSION +
                    "uniform mat4 ProjMtx;\n" +
                    "in vec2 Position;\n" +
                    "in vec2 TexCoord;\n" +
                    "in vec4 Color;\n" +
                    "out vec2 Frag_UV;\n" +
                    "out vec4 Frag_Color;\n" +
                    "void main() {\n" +
                    "   Frag_UV = TexCoord;\n" +
                    "   Frag_Color = Color;\n" +
                    "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" +
                    "}\n";
    String fragment_shader =
            NK_SHADER_VERSION +
                    "precision mediump float;\n" +
                    "uniform sampler2D Texture;\n" +
                    "in vec2 Frag_UV;\n" +
                    "in vec4 Frag_Color;\n" +
                    "out vec4 Out_Color;\n" +
                    "void main(){\n" +
                    "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" +
                    "}\n";

    nk_buffer_init(NuklearContainer.cmds, NuklearContainer.ALLOCATOR, BUFFER_INITIAL_SIZE);
    m_Program = glCreateProgram();
    m_Vertex_Shader = glCreateShader(GL_VERTEX_SHADER);
    m_Fragment_Shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(m_Vertex_Shader, vertex_shader);
    glShaderSource(m_Fragment_Shader, fragment_shader);
    glCompileShader(m_Vertex_Shader);
    glCompileShader(m_Fragment_Shader);
    if (glGetShaderi(m_Vertex_Shader, GL_COMPILE_STATUS) != GL_TRUE)
    {
        throw new IllegalStateException();
    }
    if (glGetShaderi(m_Fragment_Shader, GL_COMPILE_STATUS) != GL_TRUE)
    {
        throw new IllegalStateException();
    }
    glAttachShader(m_Program, m_Vertex_Shader);
    glAttachShader(m_Program, m_Fragment_Shader);
    glLinkProgram(m_Program);
    if (glGetProgrami(m_Program, GL_LINK_STATUS) != GL_TRUE)
    {
        throw new IllegalStateException();
    }

    m_Uniform_Texture = glGetUniformLocation(m_Program, "Texture");
    m_Uniform_Proj = glGetUniformLocation(m_Program, "ProjMtx");
    int attrib_pos = glGetAttribLocation(m_Program, "Position");
    int attrib_uv = glGetAttribLocation(m_Program, "TexCoord");
    int attrib_col = glGetAttribLocation(m_Program, "Color");

    {
        // buffer setup
        m_Vbo = glGenBuffers();
        m_Ebo = glGenBuffers();
        m_Vao = glGenVertexArrays();

        glBindVertexArray(m_Vao);
        glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);

        glEnableVertexAttribArray(attrib_pos);
        glEnableVertexAttribArray(attrib_uv);
        glEnableVertexAttribArray(attrib_col);

        glVertexAttribPointer(attrib_pos, 2, GL_FLOAT, false, 20, 0);
        glVertexAttribPointer(attrib_uv, 2, GL_FLOAT, false, 20, 8);
        glVertexAttribPointer(attrib_col, 4, GL_UNSIGNED_BYTE, true, 20, 16);
    }

    {
        // null texture setup
        int nullTexID = glGenTextures();

        NuklearContainer.null_texture.texture().id(nullTexID);
        NuklearContainer.null_texture.uv().set(0.5f, 0.5f);

        glBindTexture(GL_TEXTURE_2D, nullTexID);
        try (MemoryStack stack = stackPush())
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, stack.ints(0xFFFFFFFF));
        }
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    }

    glBindTexture(GL_TEXTURE_2D, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    FontInit();
}

private void FontInit()
{
    int BITMAP_W = 1024;
    int BITMAP_H = 1024;

    int FONT_HEIGHT = 18;
    int fontTexID   = glGenTextures();

    STBTTFontinfo fontInfo = STBTTFontinfo.create();
    STBTTPackedchar.Buffer cdata    = STBTTPackedchar.create(95);

    float scale;
    float descent;

    try (MemoryStack stack = stackPush()) {
        stbtt_InitFont(fontInfo, ttf);
        scale = stbtt_ScaleForPixelHeight(fontInfo, FONT_HEIGHT);

        IntBuffer d = stack.mallocInt(1);
        stbtt_GetFontVMetrics(fontInfo, null, d, null);
        descent = d.get(0) * scale;

        ByteBuffer bitmap = memAlloc(BITMAP_W * BITMAP_H);

        STBTTPackContext pc = STBTTPackContext.mallocStack(stack);
        stbtt_PackBegin(pc, bitmap, BITMAP_W, BITMAP_H, 0, 1, NULL);
        stbtt_PackSetOversampling(pc, 4, 4);
        stbtt_PackFontRange(pc, ttf, 0, FONT_HEIGHT, 32, cdata);
        stbtt_PackEnd(pc);

        // Convert R8 to RGBA8
        ByteBuffer texture = memAlloc(BITMAP_W * BITMAP_H * 4);
        for (int i = 0; i < bitmap.capacity(); i++) {
            texture.putInt((bitmap.get(i) << 24) | 0x00FFFFFF);
        }
        texture.flip();

        glBindTexture(GL_TEXTURE_2D, fontTexID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BITMAP_W, BITMAP_H, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        memFree(texture);
        memFree(bitmap);
    }

    NuklearContainer.default_font
            .width((handle, h, text, len) -> {
                float text_width = 0;
                try (MemoryStack stack = stackPush()) {
                    IntBuffer unicode = stack.mallocInt(1);

                    int glyph_len = nnk_utf_decode(text, memAddress(unicode), len);
                    int text_len  = glyph_len;

                    if (glyph_len == 0) {
                        return 0;
                    }

                    IntBuffer advance = stack.mallocInt(1);
                    while (text_len <= len && glyph_len != 0) {
                        if (unicode.get(0) == NK_UTF_INVALID) {
                            break;
                        }

                        /* query currently drawn glyph information */
                        stbtt_GetCodepointHMetrics(fontInfo, unicode.get(0), advance, null);
                        text_width += advance.get(0) * scale;

                        /* offset next glyph */
                        glyph_len = nnk_utf_decode(text + text_len, memAddress(unicode), len - text_len);
                        text_len += glyph_len;
                    }
                }
                return text_width;
            })
            .height(FONT_HEIGHT)
            .query((handle, font_height, glyph, codepoint, next_codepoint) -> {
                try (MemoryStack stack = stackPush()) {
                    FloatBuffer x = stack.floats(0.0f);
                    FloatBuffer y = stack.floats(0.0f);

                    STBTTAlignedQuad q       = STBTTAlignedQuad.mallocStack(stack);
                    IntBuffer        advance = stack.mallocInt(1);

                    stbtt_GetPackedQuad(cdata, BITMAP_W, BITMAP_H, codepoint - 32, x, y, q, false);
                    stbtt_GetCodepointHMetrics(fontInfo, codepoint, advance, null);

                    NkUserFontGlyph ufg = NkUserFontGlyph.create(glyph);

                    ufg.width(q.x1() - q.x0());
                    ufg.height(q.y1() - q.y0());
                    ufg.offset().set(q.x0(), q.y0() + (FONT_HEIGHT + descent));
                    ufg.xadvance(advance.get(0) * scale);
                    ufg.uv(0).set(q.s0(), q.t0());
                    ufg.uv(1).set(q.s1(), q.t1());
                }
            })
            .texture(it -> it
                    .id(fontTexID));

    nk_style_set_font(NuklearContainer.ctx, NuklearContainer.default_font);
}

public void Render()
{
    try (MemoryStack stack = stackPush())
    {
        // setup global state
        glEnable(GL_BLEND);
        glBlendEquation(GL_FUNC_ADD);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_SCISSOR_TEST);
        glActiveTexture(GL_TEXTURE0);

        // setup program
        glUseProgram(m_Program);
        glUniform1i(m_Uniform_Texture, 0);
        glUniformMatrix4fv(m_Uniform_Proj, false, stack.floats(
                2.0f / Window.m_Width, 0.0f, 0.0f, 0.0f,
                0.0f, -2.0f / Window.m_Height, 0.0f, 0.0f,
                0.0f, 0.0f, -1.0f, 0.0f,
                -1.0f, 1.0f, 0.0f, 1.0f
        ));
        glViewport(0, 0, Window.m_DisplayWidth, Window.m_DisplayHeight);
    }

    {
        // convert from command queue into draw list and draw to screen

        // allocate vertex and element buffer
        glBindVertexArray(m_Vao);
        glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);

        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, GL_STREAM_DRAW);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, GL_STREAM_DRAW);

        // load draw vertices & elements directly into vertex + element buffer
        ByteBuffer vertices = Objects.requireNonNull(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, max_vertex_buffer, null));
        ByteBuffer elements = Objects.requireNonNull(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY, max_element_buffer, null));
        try (MemoryStack stack = stackPush())
        {
            // fill convert configuration
            NkConvertConfig config = NkConvertConfig.callocStack(stack)
                    .vertex_layout(VERTEX_LAYOUT)
                    .vertex_size(20)
                    .vertex_alignment(4)
                    .null_texture(NuklearContainer.null_texture)
                    .circle_segment_count(22)
                    .curve_segment_count(22)
                    .arc_segment_count(22)
                    .global_alpha(1.0f)
                    .shape_AA(NK_ANTI_ALIASING_ON)
                    .line_AA(NK_ANTI_ALIASING_ON);

            // setup buffers to load vertices and elements
            NkBuffer vbuf = NkBuffer.mallocStack(stack);
            NkBuffer ebuf = NkBuffer.mallocStack(stack);

            nk_buffer_init_fixed(vbuf, vertices/*, max_vertex_buffer*/);
            nk_buffer_init_fixed(ebuf, elements/*, max_element_buffer*/);
            nk_convert(NuklearContainer.ctx, NuklearContainer.cmds, vbuf, ebuf, config);
        }
        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
        glUnmapBuffer(GL_ARRAY_BUFFER);

        // iterate over and execute each draw command
        float fb_scale_x = (float) Window.m_DisplayWidth / (float) Window.m_Width;
        float fb_scale_y = (float) Window.m_DisplayHeight / (float) Window.m_Height;

        long offset = NULL;
        for (NkDrawCommand cmd = nk__draw_begin(NuklearContainer.ctx, NuklearContainer.cmds); cmd != null; cmd = nk__draw_next(cmd, NuklearContainer.cmds, NuklearContainer.ctx))
        {
            if (cmd.elem_count() == 0)
            {
                continue;
            }
            glBindTexture(GL_TEXTURE_2D, cmd.texture().id());
            glScissor(
                    (int) (cmd.clip_rect().x() * fb_scale_x),
                    (int) ((Window.m_Height - (int) (cmd.clip_rect().y() + cmd.clip_rect().h())) * fb_scale_y),
                    (int) (cmd.clip_rect().w() * fb_scale_x),
                    (int) (cmd.clip_rect().h() * fb_scale_y)
            );
            glDrawElements(GL_TRIANGLES, cmd.elem_count(), GL_UNSIGNED_SHORT, offset);
            offset += cmd.elem_count() * 2;
        }
        nk_clear(NuklearContainer.ctx);
    }

    glUseProgram(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    glDisable(GL_BLEND);
    glDisable(GL_SCISSOR_TEST);
}

private boolean m_Initialized;
public boolean IsInitialized() { return m_Initialized; }
private int BUFFER_INITIAL_SIZE = 4 * 1024;
long max_vertex_buffer = 512 * 1024;
long max_element_buffer = 128 * 1024;

private NkDrawVertexLayoutElement.Buffer VERTEX_LAYOUT = NkDrawVertexLayoutElement.create(4)
        .position(0).attribute(NK_VERTEX_POSITION).format(NK_FORMAT_FLOAT).offset(0)
        .position(1).attribute(NK_VERTEX_TEXCOORD).format(NK_FORMAT_FLOAT).offset(8)
        .position(2).attribute(NK_VERTEX_COLOR).format(NK_FORMAT_R8G8B8A8).offset(16)
        .position(3).attribute(NK_VERTEX_ATTRIBUTE_COUNT).format(NK_FORMAT_COUNT).offset(0)
        .flip();

private ByteBuffer ttf;
}

I'm really sorry if the code is huge, but even just the GLFWDemo is 600+ lines long.

0

There are 0 best solutions below