Skip to content

Instantly share code, notes, and snippets.

@mudlee
Created December 24, 2019 13:23
Show Gist options
  • Save mudlee/c32e5e939fac792dc1e7721376116a0f to your computer and use it in GitHub Desktop.
Save mudlee/c32e5e939fac792dc1e7721376116a0f to your computer and use it in GitHub Desktop.
Nuklear code
package spck.engine.ui;
import org.lwjgl.BufferUtils;
import org.lwjgl.nuklear.*;
import org.lwjgl.opengl.GL41;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spck.engine.Engine;
import spck.engine.bus.LifeCycle;
import spck.engine.bus.MessageBus;
import spck.engine.util.ResourceLoader;
import spck.engine.window.GLFWWindow;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Objects;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.stb.STBTruetype.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
public class NuklearHandler {
private static final NkAllocator ALLOCATOR;
private static final NkDrawVertexLayoutElement.Buffer VERTEX_LAYOUT;
private static final Logger LOGGER = LoggerFactory.getLogger(NuklearHandler.class);
private static final int BUFFER_INITIAL_SIZE = 4 * 1024;
private static final int MAX_VERTEX_BUFFER = 512 * 1024;
private static final int MAX_ELEMENT_BUFFER = 128 * 1024;
private final NkContext ctx = NkContext.create();
private final NkUserFont default_font = NkUserFont.create();
private final NkBuffer cmds = NkBuffer.create();
private final NkDrawNullTexture null_texture = NkDrawNullTexture.create();
private final GLFWWindow window;
private int vbo, vao, ebo;
private int prog;
private int vert_shdr;
private int frag_shdr;
private int uniform_tex;
private int uniform_proj;
static {
ALLOCATOR = NkAllocator.create()
.alloc((handle, old, size) -> nmemAllocChecked(size))
.mfree((handle, ptr) -> nmemFree(ptr));
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();
}
public NuklearHandler(GLFWWindow window) {
this.window = window;
MessageBus.register(LifeCycle.GAME_START.eventID(), this::onStart);
MessageBus.register(LifeCycle.FRAME_START.eventID(), this::onFrameStart);
MessageBus.register(LifeCycle.BEFORE_BUFFER_SWAP.eventID(), this::onBeforeBufferSwap);
}
private void onBeforeBufferSwap() {
//render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}
private void onStart() {
LOGGER.debug("Initializing {}...", NuklearHandler.class.getName());
setupWindow(window.getId());
initStb();
}
private static final int EASY = 0;
private static final int HARD = 1;
private int op = EASY;
private IntBuffer compression = BufferUtils.createIntBuffer(1).put(0, 20);
NkColorf background = NkColorf.create()
.r(0.10f)
.g(0.18f)
.b(0.24f)
.a(1.0f);
private void onFrameStart() {
nk_input_begin(ctx);
glfwPollEvents();
NkMouse mouse = ctx.input().mouse();
if (mouse.grab()) {
glfwSetInputMode(window.getId(), GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
} else if (mouse.grabbed()) {
float prevX = mouse.prev().x();
float prevY = mouse.prev().y();
glfwSetCursorPos(window.getId(), prevX, prevY);
mouse.pos().x(prevX);
mouse.pos().y(prevY);
} else if (mouse.ungrab()) {
glfwSetInputMode(window.getId(), GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
nk_input_end(ctx);
int x = 50;
int y = 50;
try (MemoryStack stack = stackPush()) {
NkRect rect = NkRect.mallocStack(stack);
if (nk_begin(
ctx,
"Demo",
nk_rect(x, y, 230, 250, rect),
NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE
)) {
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button")) {
System.out.println("button pressed");
}
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) {
op = EASY;
}
if (nk_option_label(ctx, "hard", op == HARD)) {
op = HARD;
}
nk_layout_row_dynamic(ctx, 25, 1);
nk_property_int(ctx, "Compression:", 0, compression, 100, 10, 1);
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, nk_rgb_cf(background, NkColor.mallocStack(stack)), NkVec2.mallocStack(stack).set(nk_widget_width(ctx), 400))) {
nk_layout_row_dynamic(ctx, 120, 1);
nk_color_picker(ctx, background, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
background
.r(nk_propertyf(ctx, "#R:", 0, background.r(), 1.0f, 0.01f, 0.005f))
.g(nk_propertyf(ctx, "#G:", 0, background.g(), 1.0f, 0.01f, 0.005f))
.b(nk_propertyf(ctx, "#B:", 0, background.b(), 1.0f, 0.01f, 0.005f))
.a(nk_propertyf(ctx, "#A:", 0, background.a(), 1.0f, 0.01f, 0.005f));
nk_combo_end(ctx);
}
}
nk_end(ctx);
}
render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}
private void render(int AA, int max_vertex_buffer, int max_element_buffer) {
int height = window.getHeight();
int width = window.getWidth();
int display_width = width;
int display_height = height;
try (MemoryStack stack = stackPush()) {
// setup global state
GL41.glEnable(GL41.GL_BLEND);
GL41.glBlendEquation(GL41.GL_FUNC_ADD);
GL41.glBlendFunc(GL41.GL_SRC_ALPHA, GL41.GL_ONE_MINUS_SRC_ALPHA);
GL41.glDisable(GL41.GL_CULL_FACE);
GL41.glDisable(GL41.GL_DEPTH_TEST);
GL41.glEnable(GL41.GL_SCISSOR_TEST);
GL41.glActiveTexture(GL41.GL_TEXTURE0);
// setup program
GL41.glUseProgram(prog);
GL41.glUniform1i(uniform_tex, 0);
GL41.glUniformMatrix4fv(uniform_proj, false, stack.floats(
2.0f / width, 0.0f, 0.0f, 0.0f,
0.0f, -2.0f / height, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f
));
GL41.glViewport(0, 0, display_width, display_height);
}
{
// convert from command queue into draw list and draw to screen
// allocate vertex and element buffer
GL41.glBindVertexArray(vao);
GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
GL41.glBindBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL41.glBufferData(GL41.GL_ARRAY_BUFFER, max_vertex_buffer, GL41.GL_STREAM_DRAW);
GL41.glBufferData(GL41.GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, GL41.GL_STREAM_DRAW);
// load draw vertices & elements directly into vertex + element buffer
ByteBuffer vertices = Objects.requireNonNull(GL41.glMapBuffer(GL41.GL_ARRAY_BUFFER, GL41.GL_WRITE_ONLY, max_vertex_buffer, null));
ByteBuffer elements = Objects.requireNonNull(GL41.glMapBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER, GL41.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(null_texture)
.circle_segment_count(22)
.curve_segment_count(22)
.arc_segment_count(22)
.global_alpha(1.0f)
.shape_AA(AA)
.line_AA(AA);
// 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(ctx, cmds, vbuf, ebuf, config);
}
GL41.glUnmapBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER);
GL41.glUnmapBuffer(GL41.GL_ARRAY_BUFFER);
// iterate over and execute each draw command
float fb_scale_x = 1;//(float)display_width / (float)width;
float fb_scale_y = 1;//(float)display_height / (float)height;
long offset = NULL;
for (NkDrawCommand cmd = nk__draw_begin(ctx, cmds); cmd != null; cmd = nk__draw_next(cmd, cmds, ctx)) {
if (cmd.elem_count() == 0) {
continue;
}
GL41.glBindTexture(GL41.GL_TEXTURE_2D, cmd.texture().id());
GL41.glScissor(
(int) (cmd.clip_rect().x() * fb_scale_x),
(int) ((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)
);
GL41.glDrawElements(GL41.GL_TRIANGLES, cmd.elem_count(), GL41.GL_UNSIGNED_SHORT, offset);
offset += cmd.elem_count() * 2;
}
nk_clear(ctx);
}
// default OpenGL state
GL41.glUseProgram(0);
GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
GL41.glBindBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER, 0);
GL41.glBindVertexArray(0);
GL41.glDisable(GL41.GL_BLEND);
GL41.glDisable(GL41.GL_SCISSOR_TEST);
}
private void initStb() {
LOGGER.debug("Creating font...");
ByteBuffer ttf = ResourceLoader.loadToByteBuffer("/fonts/GeosansLight.ttf");
int BITMAP_W = 1024;
int BITMAP_H = 1024;
int FONT_HEIGHT = 18;
int fontTexID = GL41.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();
GL41.glBindTexture(GL41.GL_TEXTURE_2D, fontTexID);
GL41.glTexImage2D(GL41.GL_TEXTURE_2D, 0, GL41.GL_RGBA8, BITMAP_W, BITMAP_H, 0, GL41.GL_RGBA, GL41.GL_UNSIGNED_INT_8_8_8_8_REV, texture);
GL41.glTexParameteri(GL41.GL_TEXTURE_2D, GL41.GL_TEXTURE_MAG_FILTER, GL41.GL_LINEAR);
GL41.glTexParameteri(GL41.GL_TEXTURE_2D, GL41.GL_TEXTURE_MIN_FILTER, GL41.GL_LINEAR);
memFree(texture);
memFree(bitmap);
}
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(ctx, default_font);
}
private NkContext setupWindow(long win) {
glfwSetScrollCallback(win, (window, xoffset, yoffset) -> {
try (MemoryStack stack = stackPush()) {
NkVec2 scroll = NkVec2.mallocStack(stack)
.x((float) xoffset)
.y((float) yoffset);
nk_input_scroll(ctx, scroll);
}
});
glfwSetCharCallback(win, (window, codepoint) -> nk_input_unicode(ctx, codepoint));
/*glfwSetKeyCallback(win, (window, key, scancode, action, mods) -> {
boolean press = action == GLFW_PRESS;
switch (key) {
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, true);
break;
case GLFW_KEY_DELETE:
nk_input_key(ctx, NK_KEY_DEL, press);
break;
case GLFW_KEY_ENTER:
nk_input_key(ctx, NK_KEY_ENTER, press);
break;
case GLFW_KEY_TAB:
nk_input_key(ctx, NK_KEY_TAB, press);
break;
case GLFW_KEY_BACKSPACE:
nk_input_key(ctx, NK_KEY_BACKSPACE, press);
break;
case GLFW_KEY_UP:
nk_input_key(ctx, NK_KEY_UP, press);
break;
case GLFW_KEY_DOWN:
nk_input_key(ctx, NK_KEY_DOWN, press);
break;
case GLFW_KEY_HOME:
nk_input_key(ctx, NK_KEY_TEXT_START, press);
nk_input_key(ctx, NK_KEY_SCROLL_START, press);
break;
case GLFW_KEY_END:
nk_input_key(ctx, NK_KEY_TEXT_END, press);
nk_input_key(ctx, NK_KEY_SCROLL_END, press);
break;
case GLFW_KEY_PAGE_DOWN:
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, press);
break;
case GLFW_KEY_PAGE_UP:
nk_input_key(ctx, NK_KEY_SCROLL_UP, press);
break;
case GLFW_KEY_LEFT_SHIFT:
case GLFW_KEY_RIGHT_SHIFT:
nk_input_key(ctx, NK_KEY_SHIFT, press);
break;
case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_CONTROL:
if (press) {
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS);
} else {
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_COPY, false);
nk_input_key(ctx, NK_KEY_PASTE, false);
nk_input_key(ctx, NK_KEY_CUT, false);
nk_input_key(ctx, NK_KEY_SHIFT, false);
}
break;
}
});
glfwSetCursorPosCallback(win, (window, xpos, ypos) -> nk_input_motion(ctx, (int)xpos, (int)ypos));
glfwSetMouseButtonCallback(win, (window, button, action, mods) -> {
try (MemoryStack stack = stackPush()) {
DoubleBuffer cx = stack.mallocDouble(1);
DoubleBuffer cy = stack.mallocDouble(1);
glfwGetCursorPos(window, cx, cy);
int x = (int)cx.get(0);
int y = (int)cy.get(0);
int nkButton;
switch (button) {
case GLFW_MOUSE_BUTTON_RIGHT:
nkButton = NK_BUTTON_RIGHT;
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
nkButton = NK_BUTTON_MIDDLE;
break;
default:
nkButton = NK_BUTTON_LEFT;
}
nk_input_button(ctx, nkButton, x, y, action == GLFW_PRESS);
}
});*/
nk_init(ctx, ALLOCATOR, null);
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(win, str);
}
})
.paste((handle, edit) -> {
long text = nglfwGetClipboardString(win);
if (text != NULL) {
nnk_textedit_paste(edit, text, nnk_strlen(text));
}
});
setupContext();
return ctx;
}
private void setupContext() {
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(cmds, ALLOCATOR, BUFFER_INITIAL_SIZE);
prog = GL41.glCreateProgram();
vert_shdr = GL41.glCreateShader(GL41.GL_VERTEX_SHADER);
frag_shdr = GL41.glCreateShader(GL41.GL_FRAGMENT_SHADER);
GL41.glShaderSource(vert_shdr, vertex_shader);
GL41.glShaderSource(frag_shdr, fragment_shader);
GL41.glCompileShader(vert_shdr);
GL41.glCompileShader(frag_shdr);
if (GL41.glGetShaderi(vert_shdr, GL41.GL_COMPILE_STATUS) != GL41.GL_TRUE) {
throw new IllegalStateException();
}
if (GL41.glGetShaderi(frag_shdr, GL41.GL_COMPILE_STATUS) != GL41.GL_TRUE) {
throw new IllegalStateException();
}
GL41.glAttachShader(prog, vert_shdr);
GL41.glAttachShader(prog, frag_shdr);
GL41.glLinkProgram(prog);
if (GL41.glGetProgrami(prog, GL41.GL_LINK_STATUS) != GL41.GL_TRUE) {
throw new IllegalStateException();
}
uniform_tex = GL41.glGetUniformLocation(prog, "Texture");
uniform_proj = GL41.glGetUniformLocation(prog, "ProjMtx");
int attrib_pos = GL41.glGetAttribLocation(prog, "Position");
int attrib_uv = GL41.glGetAttribLocation(prog, "TexCoord");
int attrib_col = GL41.glGetAttribLocation(prog, "Color");
{
// buffer setup
vbo = GL41.glGenBuffers();
ebo = GL41.glGenBuffers();
vao = GL41.glGenVertexArrays();
GL41.glBindVertexArray(vao);
GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
GL41.glBindBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL41.glEnableVertexAttribArray(attrib_pos);
GL41.glEnableVertexAttribArray(attrib_uv);
GL41.glEnableVertexAttribArray(attrib_col);
GL41.glVertexAttribPointer(attrib_pos, 2, GL41.GL_FLOAT, false, 20, 0);
GL41.glVertexAttribPointer(attrib_uv, 2, GL41.GL_FLOAT, false, 20, 8);
GL41.glVertexAttribPointer(attrib_col, 4, GL41.GL_UNSIGNED_BYTE, true, 20, 16);
}
{
// null texture setup
int nullTexID = GL41.glGenTextures();
null_texture.texture().id(nullTexID);
null_texture.uv().set(0.5f, 0.5f);
GL41.glBindTexture(GL41.GL_TEXTURE_2D, nullTexID);
try (MemoryStack stack = stackPush()) {
GL41.glTexImage2D(GL41.GL_TEXTURE_2D, 0, GL41.GL_RGBA8, 1, 1, 0, GL41.GL_RGBA, GL41.GL_UNSIGNED_INT_8_8_8_8_REV, stack.ints(0xFFFFFFFF));
}
GL41.glTexParameteri(GL41.GL_TEXTURE_2D, GL41.GL_TEXTURE_MAG_FILTER, GL41.GL_NEAREST);
GL41.glTexParameteri(GL41.GL_TEXTURE_2D, GL41.GL_TEXTURE_MIN_FILTER, GL41.GL_NEAREST);
}
GL41.glBindTexture(GL41.GL_TEXTURE_2D, 0);
GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
GL41.glBindBuffer(GL41.GL_ELEMENT_ARRAY_BUFFER, 0);
GL41.glBindVertexArray(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment