Skip to content

Instantly share code, notes, and snippets.

@ryuukk
Created June 26, 2022 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryuukk/1c8b7af3265389ed94467bef2fd70d30 to your computer and use it in GitHub Desktop.
Save ryuukk/1c8b7af3265389ed94467bef2fd70d30 to your computer and use it in GitHub Desktop.
struct UIRenderer
{
enum MAX_C = 8192;
enum MAX_V = 512 * 1024;
enum MAX_I = 128 * 1024;
Context* ctx;
ShaderProgram program_nuklear;
uint nk_vao;
uint nk_vbo;
uint nk_ibo;
nk.nk_context nk_ctx = void;
nk.nk_allocator nk_allocator = void;
nk.nk_buffer nk_commands = void;
nk.nk_buffer nk_vertices = void;
nk.nk_buffer nk_indices = void;
nk.nk_font_atlas nk_atlas;
nk.struct_nk_vec2 tmp_scroll = { x: 0, y: 0 };
int attrib_pos;
int attrib_uv;
int attrib_col;
void create_gl_ressource()
{
import gl = dawn.gl;
program_nuklear.create(VS, FS);
attrib_pos = gl.glGetAttribLocation(program_nuklear.program, "aPos");
attrib_uv = gl.glGetAttribLocation(program_nuklear.program, "aTexCoord");
attrib_col = gl.glGetAttribLocation(program_nuklear.program, "aColor");
gl.glGenBuffers(1, &nk_vbo);
gl.glGenBuffers(1, &nk_ibo);
gl.glGenVertexArrays(1, &nk_vao);
gl.glBindVertexArray(nk_vao);
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, nk_vbo);
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, nk_ibo);
gl.glEnableVertexAttribArray(0);
gl.glEnableVertexAttribArray(1);
gl.glEnableVertexAttribArray(2);
gl.glVertexAttribPointer(attrib_pos, 2, gl.GL_FLOAT, gl.GL_FALSE, 8 * float.sizeof, cast(uint*) (0 * float.sizeof));
gl.glVertexAttribPointer(attrib_uv, 2, gl.GL_FLOAT, gl.GL_FALSE, 8 * float.sizeof, cast(uint*) (2 * float.sizeof));
gl.glVertexAttribPointer(attrib_col, 4, gl.GL_FLOAT, gl.GL_FALSE, 8 * float.sizeof, cast(uint*) (4 * float.sizeof));
gl.glBindTexture(gl.GL_TEXTURE_2D, 0);
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0);
gl.glBindVertexArray(0);
}
void create_nk_ressource()
{
nk_allocator.userdata.ptr = ctx;
nk_allocator.alloc = &dnk_allocate;
nk_allocator.free = &dnk_free;
nk.nk_font_atlas fontAtlas = void;
nk.nk_font_atlas_init(&fontAtlas, &nk_allocator);
nk.nk_font_atlas_begin(&fontAtlas);
auto fontConfig = nk.nk_font_config(16.0);
fontConfig.oversample_h = 6;
fontConfig.oversample_v = 6;
auto font = nk.nk_font_atlas_add_default(&fontAtlas, 16.0, &fontConfig);
// create tex
int imgWidth = 0;
int imgHeight = 0;
auto img = nk.nk_font_atlas_bake(&fontAtlas, &imgWidth, &imgHeight, nk.NK_FONT_ATLAS_RGBA32);
auto atlasTex = dawn.texture.create_texture(imgWidth, imgHeight, cast(ubyte*) img);
LINFO("font tex: {}:{}", imgWidth, imgHeight);
nk.nk_font_atlas_end(&fontAtlas, nk.nk_handle_id(atlasTex.gl_handle), null);
if (nk.nk_init(&nk_ctx, &nk_allocator, &font.handle) == 0) {
// if (nk.test() == 0) {
panic("problem with nk");
}
else
{
nk.nk_buffer_init(&nk_commands, &nk_allocator, MAX_C);
nk.nk_buffer_init(&nk_vertices, &nk_allocator, MAX_V);
nk.nk_buffer_init(&nk_indices, &nk_allocator, MAX_I);
}
}
void begin()
{
nk.nk_input_begin(&nk_ctx);
auto cursorPosX = ctx.engine.input.mouse_x;
auto cursorPosY = ctx.engine.input.mouse_y;
nk.nk_input_motion(&nk_ctx, cursorPosX, cursorPosY);
nk.nk_input_button(&nk_ctx, nk.NK_BUTTON_LEFT, cursorPosX, cursorPosY, ctx.engine.input.mouse_pressed ? 1 : 0);
// TODO: middle, right
nk.nk_input_scroll(&nk_ctx, tmp_scroll);
tmp_scroll = nk.nk_vec2(0,0);
nk.nk_input_end(&nk_ctx);
}
void render()
{
import gl = dawn.gl;
gl.glEnable(gl.GL_BLEND);
gl.glBlendEquation(gl.GL_FUNC_ADD);
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);
gl.glDisable(gl.GL_CULL_FACE);
gl.glDisable(gl.GL_DEPTH_TEST);
gl.glEnable(gl.GL_SCISSOR_TEST);
gl.glActiveTexture(gl.GL_TEXTURE0);
nk.nk_draw_vertex_layout_element[4] vertexLayout = [
{ attribute: nk.NK_VERTEX_POSITION, format: nk.NK_FORMAT_FLOAT, offset: 0 },
{ attribute: nk.NK_VERTEX_TEXCOORD, format: nk.NK_FORMAT_FLOAT, offset: 8 },
{ attribute: nk.NK_VERTEX_COLOR, format: nk.NK_FORMAT_R32G32B32A32_FLOAT, offset: 16 },
// end of vertex layout
{ attribute: nk.NK_VERTEX_ATTRIBUTE_COUNT, format: nk.NK_FORMAT_COUNT, offset: 0 },
];
nk.nk_convert_config convertConfig = {
global_alpha: 1.0,
line_AA: nk.NK_ANTI_ALIASING_ON,
shape_AA: nk.NK_ANTI_ALIASING_ON,
vertex_layout: vertexLayout.ptr,
vertex_size: 8 * float.sizeof,
vertex_alignment: float.alignof,
circle_segment_count: 22,
curve_segment_count: 22,
arc_segment_count: 22,
nulll: {
texture: { id: 0 },
uv: { x: 0, y: 0 }
}
};
if (nk.nk_convert(&nk_ctx, &nk_commands, &nk_vertices, &nk_indices, &convertConfig) != 0) {
panic("nk_convert error");
}
float[4][4] ortho = [
[2.0, 0.0, 0.0, 0.0],
[0.0,-2.0, 0.0, 0.0],
[0.0, 0.0,-1.0, 0.0],
[-1.0,1.0, 0.0, 1.0],
];
ortho[0][0] = ortho[0][0] / cast(float)(ctx.engine.backbuffer_width);
ortho[1][1] = ortho[1][1] / cast(float)(ctx.engine.backbuffer_height);
auto ptr = &ortho[0][0];
auto mptr = cast(mat4*)(ptr);
program_nuklear.bind();
program_nuklear.set_uniformi("uTexture", 0);
program_nuklear.set_uniform_mat4("projMatrix", *mptr);
gl.glBindVertexArray(nk_vao);
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, nk_vbo);
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, nk_ibo);
gl.glBufferData(gl.GL_ARRAY_BUFFER, cast(uint)(nk.nk_buffer_total(&nk_vertices)), nk.nk_buffer_memory_const(&nk_vertices), gl.GL_STREAM_DRAW);
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, cast(uint)(nk.nk_buffer_total(&nk_indices)), nk.nk_buffer_memory_const(&nk_indices), gl.GL_STREAM_DRAW);
auto cmd = nk.nk__draw_begin(&nk_ctx, &nk_commands);
uint offset = 0;
while(cmd) {
auto count = cmd.elem_count;
auto tex = cmd.texture.id;
if (count > 0) {
program_nuklear.set_uniformi("useTexture", tex != 0 ? 1 : 0);
gl.glBindTexture(gl.GL_TEXTURE_2D,cast(uint) tex);
auto clip = cmd.clip_rect;
gl.glScissor(
cast(int)(clip.x),
cast(int)(cast(float)(engine.backbuffer_height) - (clip.y + clip.h)),
cast(int)(clip.w),
cast(int)(clip.h),
);
gl.glDrawElements(gl.GL_TRIANGLES, cast(int) count, gl.GL_UNSIGNED_SHORT, cast(void*)(offset * 2));
dawn.gfx.check_gl_error();
}
offset += count;
cmd = nk.nk__draw_next(cmd, &nk_commands, &nk_ctx);
}
nk.nk_clear(&nk_ctx);
nk.nk_buffer_clear(&nk_commands);
nk.nk_buffer_clear(&nk_vertices);
nk.nk_buffer_clear(&nk_indices);
}
void create(Context* ctx)
{
this.ctx = ctx;
create_gl_ressource();
create_nk_ressource();
}
extern(C) static void* dnk_allocate(nk.nk_handle handle, void* old, nk.nk_size size)
{
if (old)
{
LWARN("need handle realloc {}", size);
}
auto ctx = cast(Context*) handle.ptr;
return ctx.engine.allocator.allocate(size);
}
extern(C) static void dnk_free(nk.nk_handle handle, void* old)
{
auto ctx = cast(Context*) handle.ptr;
if (!old)
{
LWARN("trying to free null ptr");
return;
}
ctx.engine.allocator.free(old);
}
enum VS ="
#version 300 es
in vec2 aPos;
in vec2 aTexCoord;
in vec4 aColor;
uniform mat4 projMatrix;
out vec2 texCoord;
out vec4 vertexColor;
void main() {
gl_Position = projMatrix * vec4(aPos, 0, 1);
texCoord = aTexCoord;
vertexColor = aColor;
}";
enum FS =
"
#version 300 es
precision mediump float;
in vec2 texCoord;
in vec4 vertexColor;
uniform bool useTexture;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
if (useTexture) {
fragColor = texture(uTexture, texCoord) * vertexColor;
} else {
fragColor = vertexColor;
}
}";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment