From 6736966974aea334e119cdb0b6c330066061bf91 Mon Sep 17 00:00:00 2001 From: quou Date: Fri, 27 Dec 2024 11:35:01 +1100 Subject: basic text rendering --- ui.cpp | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 ui.cpp (limited to 'ui.cpp') diff --git a/ui.cpp b/ui.cpp new file mode 100644 index 0000000..3f773f5 --- /dev/null +++ b/ui.cpp @@ -0,0 +1,275 @@ +#include "ui.hpp" + +extern "C" { +#include "memory.h" +#include "plat.h" +#include "str.h" +} + +#include + +#define mesh_size (1024 * 8) + +static int font_w = 960; +static unsigned font_data[] = { + 0x00000000, 0x00003000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0cc0c000, 0x8000301b, 0x60601803, 0x00000000, 0x20000000, + 0x0780c078, 0x83f0e01e, 0xe0783f07, 0x60000001, 0x1e018000, + 0x07e0c078, 0xe3f87e1f, 0xe0cc1e0f, 0x1e638f01, 0x1f0c6318, + 0x07e1f07e, 0xc330fc1e, 0x30cc318c, 0x021e0fc3, 0x000101e0, + 0x00e00000, 0x0000e000, 0xc00e0007, 0x3c038c00, 0x00000000, + 0x00000000, 0x00001000, 0x00000000, 0x30380000, 0x0000c070, + 0x0cc1e000, 0xc630f81b, 0xc0301806, 0x00000cc0, 0x30000000, + 0x0cc0f0cc, 0xc030f033, 0x30cc330c, 0x30000003, 0x33030000, + 0x8cc1e0cc, 0xc230cc33, 0xc0cc3308, 0x0c630600, 0x318ce3b8, + 0x0cc318cc, 0xc330b433, 0x30cc318c, 0x06060cc3, 0x00038180, + 0x00c00018, 0x8000c000, 0x000c000d, 0x30030000, 0x00000000, + 0x00000000, 0x00001800, 0x00000000, 0x300c0000, 0x0409e0c0, + 0x8481e000, 0xc3300c3f, 0x80180c06, 0x000c0781, 0x18000000, + 0x0c00c0ec, 0xc1f0d830, 0x30cc1800, 0x180c0303, 0x30060000, + 0x8cc330ec, 0xc0318c01, 0xc0cc3180, 0x0c330600, 0x318de3f8, + 0x0cc318cc, 0xc3303003, 0x3078318c, 0x0c060643, 0x0006c180, + 0x07c0f018, 0x81e0f81e, 0xf06c3701, 0x30330f00, 0x1e07c1f8, + 0x0ee37076, 0xc330fc3e, 0x30c6318c, 0x300c0fc3, 0x0e0f20c0, + 0x0001e000, 0x8180781b, 0x80180013, 0x000c1fe1, 0x0c000000, + 0x0600c0dc, 0xc300cc1c, 0xe0780c07, 0x0c0c0303, 0x180c03f0, + 0x87c330ec, 0xc1f18c01, 0xc0fc0187, 0x0c1f0600, 0x318fe358, + 0x07c3187c, 0xc330300e, 0xe030358c, 0x18060301, 0x000c6180, + 0x0cc18030, 0xc330cc33, 0xc0dc1987, 0x301b0c00, 0x330cc358, + 0x0dc198cc, 0xc3301803, 0x306c358c, 0x00060643, 0x1b060180, + 0x0000c000, 0xc0c0c01b, 0x8018001e, 0x003f0781, 0x060003f0, + 0x0300c0cc, 0xc301fc30, 0x00cc0c0c, 0x0c000003, 0x0c0c0000, + 0x8cc3f00c, 0xc0318c01, 0xc0cc3980, 0x0c330660, 0x318f6318, + 0x06c3980c, 0xc3303018, 0xc078358c, 0x30060180, 0x00000180, + 0x0cc1f000, 0x83f0cc03, 0xc0cc1981, 0x301f0c00, 0x330cc358, + 0x00c198cc, 0xc330181e, 0x3038358c, 0x300c0303, 0x318000c0, + 0x80000000, 0xc6607c3f, 0xc030000c, 0x300c0cc0, 0x03030000, + 0x0180c0cc, 0xc330c033, 0x30cc0c0c, 0x180c0303, 0x000603f0, + 0x8cc3308c, 0xc230cc33, 0xc0cc3300, 0x8c630660, 0x318e6318, + 0x0cc1f00c, 0x83303033, 0xc0cc1f07, 0x600609c0, 0x00000180, + 0x0cc19800, 0x8030cc33, 0xc0cc1f01, 0x30330cc0, 0x330cc358, + 0x00c198cc, 0x8330d830, 0xe06c1f07, 0x300c0981, 0x318000c0, + 0x0000c000, 0x8630301b, 0x6060001b, 0x300c0000, 0x01830000, + 0x0fc3f078, 0x81e0c01e, 0xe0780c07, 0x300c0301, 0x0c030000, + 0x07e33078, 0xe3f87e1f, 0xe0cc3e01, 0xfe6383c1, 0x1f0c6318, + 0x0ce3c01e, 0x01e0781e, 0xe0cc1b03, 0xc01e0fc1, 0x000001e0, + 0x07e3f000, 0xc1e0f81e, 0xf0ce1803, 0xfc338783, 0x1e0cc318, + 0x01e1f07c, 0x06e0701f, 0x80c61b03, 0x30380fc1, 0x3f800070, + 0x0000c000, 0x0000301b, 0x00000000, 0x18000000, 0x00800000, + 0x00000000, 0x00000000, 0x00000000, 0x60060000, 0x00018000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0x7f800000, + 0x00000000, 0x00000000, 0x00000f00, 0x00000000, 0x00000000, + 0x0001800c, 0x00000000, 0xf0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003c01e, 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static Texture_Id create_atlas(Device* d, Arena* a) { + int x, y; + int size = 10 * font_w; + uint8_t* pixels = (uint8_t*)arena_alloc(a, size); + void* bufmem; + Buffer_Id buf; + Texture_Id tex; + for (y = 0; y < 10; y++) { + for (x = 0; x < font_w; x++) { + int si = x + y * font_w; + unsigned bits = font_data[si >> 5]; + int bit = bits & 1 << (si & 0x1f); + pixels[si] = bit? 0xff: 0x00; + } + } + buf = d->create_buffer( + size, + Buffer_Flags::copy_src | + Buffer_Flags::cpu_readwrite + ); + bufmem = d->map_buffer(buf, 0, size); + memcpy(bufmem, pixels, size); + d->unmap_buffer(buf); + tex = d->create_texture( + texture_format_r8i, + font_w, + 10, + buf + ); + d->destroy_buffer(buf); + clear_arena(a); + return tex; +} + +static Sampler_Id create_clamped_point(Device* dev) { + Sampler_State s{}; + s.min = Filter_Mode::point; + s.mag = Filter_Mode::point; + s.address_u = Address_Mode::clamp; + s.address_v = Address_Mode::clamp; + return dev->create_sampler(s); +} + +UI* UI::create(Device* dev, Arena* a, Shader_Id sh) { + Texture_Id atlas = create_atlas(dev, a); + UI* u = (UI*)arena_alloc(a, sizeof *u); + u->init(dev, a, atlas, sh); + return u; +} + +int UI::text_width(const char* t) { + int w; + for (w = 0; *t; t++) w += 10; + return w; +} + +int UI::text_height(const char* t) { + (void)t; + return 10; +} + +void UI::init(Device* dev, Arena* a, Texture_Id at, Shader_Id sh) { + Shader* sp; + arena = a; + device = dev; + tree = 0; + atlas = at; + shader = sh; + mesh = device->create_buffer( + mesh_size, + Buffer_Flags::vertex_buffer | + Buffer_Flags::cpu_readwrite + ); + sp = &dev->get_shader(sh); + vertex_format = sp->vf; + shader_info.vert_binding = sp->binding_index("verts"); + shader_info.atlas_binding = sp->descriptor_binding("atlas"); + sampler = create_clamped_point(device); +} + +void UI::destroy() { + device->destroy_texture(atlas); + device->destroy_buffer(mesh); + device->destroy_sampler(sampler); +} + +int UI::Element::size(Type t) { + switch (t) { + case Type::label: + return sizeof(Label); + } + assert(0); + return 0; +} + +UI::Element* UI::create_element(Element::Type t) { + Element* e = (Element*)arena_alloc(arena, Element::size(t)); + e->type = t; + e->next = 0; + if (tree) + tree->next = e; + else + tree = e; + return e; +} + +UI::Label* UI::create_label(const char* t, int x, int y) { + Label* l = (Label*)create_element(Element::Type::label); + l->text = dup_string(arena, t); + l->len = string_len(t); + l->x = x; + l->y = y; + l->w = text_width(t); + l->h = text_height(t); + return l; +} + +void UI::update(Arena* s) { + +} + +int UI::render_label(const Label* l, int off) { + int vc = 6 * l->len, i; + int x = l->x; + int y = l->y; + const char* c; + float o = 10.0f * ndc[0]; + Vertex* verts = (Vertex*)device->map_buffer( + mesh, + off * sizeof(Vertex), + vc * sizeof(Vertex) + ); + for (i = 0, c = l->text; i < vc; i += 6, c++) { + float uo = (float)((*c - ' ') * 10) / (float)font_w; + float w = 10.0f / (float)font_w; + float uv[2] = { + uo, uo + w + }; + verts[i] = Vertex { + (float)x * ndc[0], (float)y * ndc[1], uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + verts[i + 1] = Vertex { + (float)x * ndc[0], (float)y * ndc[1] + o, uv[0], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + verts[i + 2] = Vertex { + (float)x * ndc[0] + o, (float)y * ndc[1] + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + verts[i + 3] = Vertex { + (float)x * ndc[0], (float)y * ndc[1], uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + verts[i + 4] = Vertex { + (float)x * ndc[0] + o, (float)y * ndc[1], uv[1], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + verts[i + 5] = Vertex { + (float)x * ndc[0] + o, (float)y * ndc[1] + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + x += 10; + } + device->unmap_buffer(mesh); + return vc; +} + +void UI::render(Arena* s, Texture_Id target) { + Element* e = tree; + int vc = 0; + Texture& t = device->get_texture(target); + ndc[0] = 4.0f / (float)t.w; + ndc[1] = 4.0f / (float)t.h; + for (; e; e = e->next) { + switch (e->type) { + case Element::Type::label: + vc += render_label((Label*)e, vc); + break; + } + } + + Pipeline_Builder pb(s); + pb.begin_rp(); + pb.rp_target(device->get_backbuffer(), Clear_Mode::restore); + Render_Pass& pass = pb.build_rp(); + + pb.begin(device); + pb.shader(shader); + pb.vertex_format(vertex_format); + pb.texture(shader_info.atlas_binding, atlas, sampler); + Pipeline& pip = pb.build(); + + Vertex_Buffer_Binding binding[] = {{ + .id = mesh, + .offset = 0, + .target = shader_info.vert_binding + }, {}}; + + Draw draw{}; + draw.verts = binding; + draw.vertex_count = vc; + draw.instance_count = 1; + device->get_ctx().submit(draw, pip, pass); +} -- cgit v1.2.3-54-g00ecf