Last active
June 18, 2020 09:58
-
-
Save nurpax/3900e05b60ae7c09f8fe900512768765 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sokol_gfx.h" | |
#include <assert.h> | |
#include "mui_renderer.h" | |
#include "mui_atlas.inl" | |
#include "HandmadeMath.h" | |
#include <string.h> | |
#define BUFFER_SIZE 16384 | |
static float tex_buf[BUFFER_SIZE * 8]; | |
static float vert_buf[BUFFER_SIZE * 8]; | |
static uint8_t color_buf[BUFFER_SIZE * 16]; | |
static uint32_t index_buf[BUFFER_SIZE * 6]; | |
static int buf_idx; | |
static sg_pipeline s_pip; | |
static sg_bindings s_bind; | |
static sg_buffer s_vbuf; | |
static sg_buffer s_vcol; | |
static sg_buffer s_vtex; | |
static sg_buffer s_ibuf; | |
/* a uniform block with a model-view-projection matrix */ | |
typedef struct { | |
hmm_mat4 mvp; | |
} params_t; | |
void r_init(void) { | |
sg_buffer_desc vbuf_desc = { .size = sizeof(vert_buf), .usage = SG_USAGE_STREAM }; | |
sg_buffer_desc vcol_desc = { .size = sizeof(color_buf), .usage = SG_USAGE_STREAM }; | |
sg_buffer_desc vtex_desc = { .size = sizeof(tex_buf), .usage = SG_USAGE_STREAM }; | |
sg_buffer_desc ibuf_desc = { | |
.size = sizeof(index_buf), | |
.type = SG_BUFFERTYPE_INDEXBUFFER, | |
.usage = SG_USAGE_STREAM | |
}; | |
s_vbuf = sg_make_buffer(&vbuf_desc); | |
s_vcol = sg_make_buffer(&vcol_desc); | |
s_vtex = sg_make_buffer(&vtex_desc); | |
s_ibuf = sg_make_buffer(&ibuf_desc); | |
sg_image img = sg_make_image(&(sg_image_desc){ | |
.width = ATLAS_WIDTH, | |
.height = ATLAS_HEIGHT, | |
.pixel_format = SG_PIXELFORMAT_R8,// RGBA8, | |
.min_filter = SG_FILTER_NEAREST, | |
.mag_filter = SG_FILTER_NEAREST, | |
.content.subimage[0][0] = { | |
.ptr = atlas_texture, | |
.size = sizeof(atlas_texture) | |
} | |
}); | |
/* define the resource bindings */ | |
s_bind = (sg_bindings){ | |
.vertex_buffers[0] = s_vbuf, | |
.vertex_buffers[1] = s_vtex, | |
.vertex_buffers[2] = s_vcol, | |
.fs_images[0] = img, | |
.index_buffer = s_ibuf | |
}; | |
/* create a shader (use vertex attribute locations) */ | |
sg_shader shd = sg_make_shader(&(sg_shader_desc){ | |
.vs.uniform_blocks[0] = { | |
.size = sizeof(params_t), | |
.uniforms = { | |
[0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 } | |
} | |
}, | |
.vs.source = | |
"#version 330\n" | |
"uniform mat4 mvp;\n" | |
"layout(location=0) in vec2 position;\n" | |
"layout(location=1) in vec2 tex0;\n" | |
"layout(location=2) in vec4 color0;\n" | |
"out vec4 color;\n" | |
"out vec2 uv;\n" | |
"void main() {\n" | |
" gl_Position = mvp * vec4(position, 0, 1);\n" | |
" color = color0;\n" | |
" uv = tex0;\n" | |
"}\n", | |
.fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_2D }, | |
.fs.source = | |
"#version 330\n" | |
"uniform sampler2D tex;\n" | |
"in vec4 color;\n" | |
"in vec2 uv;\n" | |
"out vec4 frag_color;\n" | |
"void main() {\n" | |
" float alpha = texture(tex, uv).x;" | |
" frag_color = vec4(1,1,1,alpha) * color;\n" | |
"}\n" | |
}); | |
/* create a pipeline object (default render state is fine) */ | |
s_pip = sg_make_pipeline(&(sg_pipeline_desc){ | |
.shader = shd, | |
.index_type = SG_INDEXTYPE_UINT32, | |
.layout = { | |
.attrs = { | |
[0] = { .offset=0, .buffer_index = 0, .format=SG_VERTEXFORMAT_FLOAT2 }, | |
[1] = { .offset=0, .buffer_index = 1, .format=SG_VERTEXFORMAT_FLOAT2 }, | |
[2] = { .offset=0, .buffer_index = 2, .format=SG_VERTEXFORMAT_UBYTE4N } | |
} | |
}, | |
.blend = { | |
.enabled = true, | |
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, | |
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, | |
} | |
}); | |
} | |
static void push_quad(mu_Rect dst, mu_Rect src, mu_Color color) { | |
assert(buf_idx < BUFFER_SIZE); | |
int texvert_idx = buf_idx * 8; | |
int color_idx = buf_idx * 16; | |
int element_idx = buf_idx * 4; | |
int index_idx = buf_idx * 6; | |
buf_idx++; | |
/* update texture buffer */ | |
float x = src.x / (float) ATLAS_WIDTH; | |
float y = src.y / (float) ATLAS_HEIGHT; | |
float w = src.w / (float) ATLAS_WIDTH; | |
float h = src.h / (float) ATLAS_HEIGHT; | |
tex_buf[texvert_idx + 0] = x; | |
tex_buf[texvert_idx + 1] = y; | |
tex_buf[texvert_idx + 2] = x + w; | |
tex_buf[texvert_idx + 3] = y; | |
tex_buf[texvert_idx + 4] = x; | |
tex_buf[texvert_idx + 5] = y + h; | |
tex_buf[texvert_idx + 6] = x + w; | |
tex_buf[texvert_idx + 7] = y + h; | |
/* update vertex buffer */ | |
vert_buf[texvert_idx + 0] = dst.x; | |
vert_buf[texvert_idx + 1] = dst.y; | |
vert_buf[texvert_idx + 2] = dst.x + dst.w; | |
vert_buf[texvert_idx + 3] = dst.y; | |
vert_buf[texvert_idx + 4] = dst.x; | |
vert_buf[texvert_idx + 5] = dst.y + dst.h; | |
vert_buf[texvert_idx + 6] = dst.x + dst.w; | |
vert_buf[texvert_idx + 7] = dst.y + dst.h; | |
/* update color buffer */ | |
memcpy(color_buf + color_idx + 0, &color, 4); | |
memcpy(color_buf + color_idx + 4, &color, 4); | |
memcpy(color_buf + color_idx + 8, &color, 4); | |
memcpy(color_buf + color_idx + 12, &color, 4); | |
/* update index buffer */ | |
index_buf[index_idx + 0] = element_idx + 0; | |
index_buf[index_idx + 1] = element_idx + 1; | |
index_buf[index_idx + 2] = element_idx + 2; | |
index_buf[index_idx + 3] = element_idx + 2; | |
index_buf[index_idx + 4] = element_idx + 3; | |
index_buf[index_idx + 5] = element_idx + 1; | |
} | |
void r_draw_rect(mu_Rect rect, mu_Color color) { | |
push_quad(rect, atlas[ATLAS_WHITE], color); | |
} | |
void r_draw_text(const char *text, mu_Vec2 pos, mu_Color color) { | |
mu_Rect dst = { pos.x, pos.y, 0, 0 }; | |
for (const char *p = text; *p; p++) { | |
if ((*p & 0xc0) == 0x80) { continue; } | |
int chr = mu_min((unsigned char) *p, 127); | |
mu_Rect src = atlas[ATLAS_FONT + chr]; | |
dst.w = src.w; | |
dst.h = src.h; | |
push_quad(dst, src, color); | |
dst.x += dst.w; | |
} | |
} | |
void r_draw_icon(int id, mu_Rect rect, mu_Color color) { | |
mu_Rect src = atlas[id]; | |
int x = rect.x + (rect.w - src.w) / 2; | |
int y = rect.y + (rect.h - src.h) / 2; | |
push_quad(mu_rect(x, y, src.w, src.h), src, color); | |
} | |
int r_get_text_width(const char *text, int len) { | |
int res = 0; | |
for (const char *p = text; *p && len--; p++) { | |
if ((*p & 0xc0) == 0x80) { continue; } | |
int chr = mu_min((unsigned char) *p, 127); | |
res += atlas[ATLAS_FONT + chr].w; | |
} | |
return res; | |
} | |
int r_get_text_height(void) { | |
return 18; | |
} | |
typedef enum { | |
CMD_DRAW, | |
CMD_CLIP | |
} cmd_type; | |
const int MAX_CMDS = 1024; | |
typedef struct { | |
cmd_type type; | |
union { | |
mu_Rect clip; | |
struct { | |
int start_buf_idx; | |
int length; | |
} draw; | |
}; | |
} draw_cmd; | |
typedef struct { | |
int cmd_idx; | |
int start_buf_idx; | |
draw_cmd cmds[MAX_CMDS]; | |
} draw_fifo; | |
void draw_fifo_start(draw_fifo* self) { | |
self->cmd_idx = 0; | |
self->start_buf_idx = 0; | |
} | |
void draw_fifo_queue_draw(draw_fifo* self, int cur_buf_idx) { | |
assert(self->cmd_idx < MAX_CMDS); | |
self->cmds[self->cmd_idx++] = (draw_cmd){ | |
.type = CMD_DRAW, | |
.draw = { | |
.start_buf_idx = self->start_buf_idx, | |
.length = cur_buf_idx - self->start_buf_idx | |
} | |
}; | |
self->start_buf_idx = cur_buf_idx; | |
} | |
void draw_fifo_queue_clip(draw_fifo* self, mu_Rect r) { | |
assert(self->cmd_idx < MAX_CMDS); | |
self->cmds[self->cmd_idx++] = (draw_cmd){ | |
.type = CMD_CLIP, | |
.clip = r | |
}; | |
} | |
void r_draw_commands(mu_Context* ctx, int width, int height) { | |
params_t vs_params; | |
vs_params.mvp = HMM_Orthographic(0.f, width, height, 0.f, -1.f, 1.f); | |
/* default pass action */ | |
sg_pass_action pass_action = { | |
.colors[0] = { .action = SG_ACTION_DONTCARE, .val = { 0.3f, 0.3f, 0.3f, 1.0f } } | |
}; | |
sg_begin_default_pass(&pass_action, width, height); | |
sg_apply_pipeline(s_pip); | |
sg_apply_bindings(&s_bind); | |
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vs_params, sizeof(vs_params)); | |
/* render */ | |
draw_fifo cmd_fifo; | |
draw_fifo_start(&cmd_fifo); | |
mu_Command *cmd = NULL; | |
while (mu_next_command(ctx, &cmd)) { | |
switch (cmd->type) { | |
case MU_COMMAND_TEXT: | |
r_draw_text(cmd->text.str, cmd->text.pos, cmd->text.color); break; | |
case MU_COMMAND_RECT: | |
r_draw_rect(cmd->rect.rect, cmd->rect.color); break; | |
case MU_COMMAND_ICON: | |
r_draw_icon(cmd->icon.id, cmd->icon.rect, cmd->icon.color); break; | |
case MU_COMMAND_CLIP: { | |
draw_fifo_queue_draw(&cmd_fifo, buf_idx); | |
draw_fifo_queue_clip(&cmd_fifo, cmd->clip.rect); | |
break; | |
} | |
} | |
} | |
draw_fifo_queue_draw(&cmd_fifo, buf_idx); | |
sg_update_buffer(s_vbuf, vert_buf, buf_idx*8*sizeof(float)); | |
sg_update_buffer(s_vtex, tex_buf, buf_idx*8*sizeof(float)); | |
sg_update_buffer(s_vcol, color_buf, buf_idx*16); | |
sg_update_buffer(s_ibuf, index_buf, buf_idx*6*sizeof(int)); | |
for (int i = 0; i < cmd_fifo.cmd_idx; i++) { | |
const draw_cmd* c = &cmd_fifo.cmds[i]; | |
switch(c->type) { | |
case CMD_DRAW: { | |
if (c->draw.length != 0) { | |
sg_draw(c->draw.start_buf_idx*6, c->draw.length*6, 1); | |
} | |
break; | |
} | |
case CMD_CLIP: { | |
mu_Rect r = c->clip; | |
sg_apply_scissor_rect(r.x, r.y, r.w, r.h, true); | |
break; | |
} | |
} | |
} | |
buf_idx = 0; | |
sg_end_pass(); | |
sg_commit(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment