summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c2.cpp1
-rw-r--r--ui.cpp329
-rw-r--r--ui.hpp89
3 files changed, 272 insertions, 147 deletions
diff --git a/c2.cpp b/c2.cpp
index e36b1cd..2e71fc8 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -126,7 +126,6 @@ extern "C" int entrypoint() {
);
clamped_linear = create_clamped_linear(dev);
ui = UI::create(dev, &ui_arena, ui_shader->id);
- ui->create_label("Hello, world", 10, 15);
assert(per_frame != 0);
uint8_t r = 0;
float rot = 0.0f;
diff --git a/ui.cpp b/ui.cpp
index bd7a90d..2060a78 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -8,9 +8,9 @@ extern "C" {
#include <string.h>
-#define mesh_size (1024 * 8)
+#define vertex_buffer_count (256)
-static int font_w = 960;
+static constexpr int font_w = 960;
static unsigned font_data[] = {
0x00000000, 0x00003000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -74,9 +74,10 @@ static unsigned font_data[] = {
0x0003c01e, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
-static Texture_Id create_atlas(Device* d, Arena* a) {
+static Texture_Id create_atlas(Device* d) {
int x, y;
- int size = 10 * font_w;
+ int w = font_w + 10;
+ int size = 10 * w;
Buffer_Id buf = d->create_buffer(
"font atlas stage",
size,
@@ -88,9 +89,16 @@ static Texture_Id create_atlas(Device* d, Arena* a) {
for (y = 0; y < 10; y++) {
for (x = 0; x < font_w; x++) {
int si = x + y * font_w;
+ int di = x + y * w;
unsigned bits = font_data[si >> 5];
int bit = bits & 1 << (si & 0x1f);
- pixels[si] = bit? 0xff: 0x00;
+ pixels[di] = bit? 0xff: 0x00;
+ }
+ }
+ /* for solid colours, one white square at the end */
+ for (y = 0; y < 10; y++) {
+ for (x = font_w; x < w; x++) {
+ pixels[x + y * w] = 0xff;
}
}
d->unmap_buffer(buf);
@@ -98,12 +106,11 @@ static Texture_Id create_atlas(Device* d, Arena* a) {
"font atlas",
texture_format_r8i,
Texture_Flags::sampleable | Texture_Flags::copy_dst,
- font_w,
+ w,
10,
buf
);
d->destroy_bufferi(buf);
- clear_arena(a);
return tex;
}
@@ -116,10 +123,176 @@ static Sampler_Id create_clamped_point(Device* dev) {
return dev->create_sampler("clamped point", s);
}
+UI::Colour::Colour(unsigned rgb, uint8_t a):
+ r((rgb >> 16) & 0xff),
+ g((rgb >> 8) & 0xff),
+ b((rgb) & 0xff),
+ a(a) {}
+
+void UI::Vertex_Buffer::init(Device* dev) {
+ buf.init(
+ dev,
+ "UI mesh",
+ vertex_buffer_count * sizeof(Vertex) * 4,
+ Buffer_Flags::vertex_buffer
+ );
+ init_indices(dev);
+ usage = 0;
+ next = 0;
+}
+
+void UI::Vertex_Buffer::init_indices(Device* dev) {
+ auto create_ind = [](uint16_t* target){
+ int i, i2, e = vertex_buffer_count * 6;
+ for (i = 0, i2 = 0; i < e; i += 6, i2 += 4) {
+ target[i ] = (uint16_t)(i2 );
+ target[i + 1] = (uint16_t)(i2 + 1);
+ target[i + 2] = (uint16_t)(i2 + 2);
+ target[i + 3] = (uint16_t)(i2 + 1);
+ target[i + 4] = (uint16_t)(i2 + 3);
+ target[i + 5] = (uint16_t)(i2 + 2);
+ }
+ };
+ int s = vertex_buffer_count * 6 * sizeof(uint16_t);
+ Buffer_Id stage = dev->create_buffer(
+ "UI mesh indices stage",
+ s,
+ Buffer_Flags::copy_src |
+ Buffer_Flags::cpu_readwrite
+ );
+ void* mem = dev->map_buffer(stage, 0, s);
+ create_ind((uint16_t*)mem);
+ indices = dev->create_buffer(
+ "UI indices",
+ s,
+ Buffer_Flags::copy_dst |
+ Buffer_Flags::index_buffer
+ );
+ Context& ctx = dev->acquire();
+ ctx.copy(indices, stage);
+ dev->submit(ctx);
+ dev->unmap_buffer(stage);
+ dev->destroy_bufferi(stage);
+}
+
+void UI::Vertex_Buffer::destroy(UI* ui) {
+ Device* dev = ui->device;
+ if (next) {
+ next->destroy(ui);
+ heap_free(ui->heap, next);
+ }
+ dev->destroy_buffer(indices);
+ buf.destroy(dev);
+}
+
+void UI::Vertex_Buffer::add_quad(
+ UI* ui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float u0,
+ float v0,
+ float u1,
+ float v1,
+ Colour col
+) {
+ Vertex* verts;
+ int index = usage * 4;
+ float r, g, b, a;
+ if (usage >= vertex_buffer_count) {
+ if (!next) {
+ next = (Vertex_Buffer*)heap_alloc(ui->heap, sizeof *next);
+ next->init(ui->device);
+ }
+ next->add_quad(ui, x, y, w, h, u0, v0, u1, v1, col);
+ return;
+ }
+ r = col.r_f();
+ g = col.g_f();
+ b = col.b_f();
+ a = col.a_f();
+ verts = &((Vertex*)buf.map(ui->device))[index];
+ verts[0] = Vertex { (float)x, (float)y, u0, v0, r, g, b, a };
+ verts[1] = Vertex { (float)x + w, (float)y, u1, v0, r, g, b, a };
+ verts[2] = Vertex { (float)x, (float)y + h, u0, v1, r, g, b, a };
+ verts[3] = Vertex { (float)x + w, (float)y + h, u1, v1, r, g, b, a };
+ buf.unmap(ui->device);
+ usage++;
+}
+
+void UI::Vertex_Buffer::add_rect(
+ UI* ui,
+ int x,
+ int y,
+ int w,
+ int h,
+ Colour col
+) {
+ constexpr float white_uv_x = (float)font_w / (float)(font_w + 10);
+ add_quad(ui, x, y, w, h, white_uv_x, 0.0f, 1.0f, 1.0f, col);
+}
+
+void UI::Vertex_Buffer::add_char(
+ UI* ui,
+ int x,
+ int y,
+ char ch,
+ Colour col
+) {
+ int off = (ch - ' ') * 10;
+ float w = (float)(font_w + 10);
+ float u0 = (float)off / w;
+ float u1 = u0 + (10.0f / w);
+ add_quad(ui, x, y, 10, 10, u0, 0.0f, u1, 1.0f, col);
+}
+
+void UI::Vertex_Buffer::add_text(
+ UI* ui,
+ int x,
+ int y,
+ const char* txt,
+ Colour col
+) {
+ for (; *txt; txt++)
+ add_char(ui, x += 10, y, *txt, col);
+}
+
+void UI::Vertex_Buffer::update_buffer(Context& ctx) {
+ buf.update(ctx);
+ if (next)
+ next->update_buffer(ctx);
+}
+
+void UI::Vertex_Buffer::draw(UI* ui, Context& ctx, Pipeline& pip, Render_Pass& rp) {
+ Vertex_Buffer_Binding binding[] = {{
+ .id = buf.gpuonly,
+ .offset = 0,
+ .target = ui->shader_info.vert_binding
+ }, {}};
+ Index_Buffer_Binding indb = {
+ .id = indices,
+ .offset = 0
+ };
+ Draw d{};
+ d.verts = binding;
+ d.inds = indb;
+ d.vertex_count = usage * 6;
+ d.instance_count = 1;
+ ctx.submit(d, pip, rp);
+ if (next)
+ next->draw(ui, ctx, pip, rp);
+ usage = 0;
+}
+
UI* UI::create(Device* dev, Arena* a, Shader_Id sh) {
- Texture_Id atlas = create_atlas(dev, a);
+ int hs;
+ Texture_Id atlas = create_atlas(dev);
UI* u = (UI*)arena_alloc(a, sizeof *u);
- u->init(dev, a, atlas, sh);
+ Heap* h = (Heap*)arena_alloc(a, sizeof *h);
+ hs = a->size - a->ptr - allocation_default_alignment - 1;
+ init_heap(h, arena_alloc(a, hs), hs);
+ u->init(dev, h, atlas, sh);
return u;
}
@@ -134,24 +307,23 @@ int UI::text_height(const char* t) {
return 10;
}
-void UI::init(Device* dev, Arena* a, Texture_Id at, Shader_Id sh) {
+void UI::init(
+ Device* dev,
+ Heap* h,
+ Texture_Id at,
+ Shader_Id sh
+) {
Shader* sp;
- arena = a;
+ heap = h;
device = dev;
- tree = 0;
atlas = at;
shader = sh;
- mesh = device->create_buffer(
- "UI Mesh",
- mesh_size,
- Buffer_Flags::vertex_buffer |
- Buffer_Flags::cpu_readwrite
- );
- config_buf = device->create_buffer(
- "UI Cbuffer",
+ mesh.init(device);
+ cbuffer.init(
+ device,
+ "UI CBuffer",
sizeof(UI_CBuffer),
- Buffer_Flags::constant_buffer |
- Buffer_Flags::cpu_readwrite
+ Buffer_Flags::constant_buffer
);
sp = &dev->get_shader(sh);
vertex_format = sp->vf;
@@ -163,110 +335,30 @@ void UI::init(Device* dev, Arena* a, Texture_Id at, Shader_Id sh) {
void UI::destroy() {
device->destroy_texture(atlas);
- device->destroy_buffer(mesh);
- device->destroy_buffer(config_buf);
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;
+ mesh.destroy(this);
+ cbuffer.destroy(device);
}
void UI::update(Arena* s) {
(void)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;
- 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, (float)y, uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
- };
- verts[i + 1] = Vertex {
- (float)x, (float)y + o, uv[0], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
- };
- verts[i + 2] = Vertex {
- (float)x + o, (float)y + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
- };
- verts[i + 3] = Vertex {
- (float)x, (float)y, uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
- };
- verts[i + 4] = Vertex {
- (float)x + o, (float)y, uv[1], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
- };
- verts[i + 5] = Vertex {
- (float)x + o, (float)y + 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;
+ int i, c = 2000;
+ Context& ctx = device->get_ctx();
Texture& t = device->get_texture(target);
- UI_CBuffer* config = (UI_CBuffer*)device->map_buffer(
- config_buf,
- 0,
- sizeof(UI_CBuffer)
- );
+ UI_CBuffer* config = (UI_CBuffer*)cbuffer.map(device);
config->projection = m4f::orth(
0.0f, (float)t.w,
0.0f, (float)t.h,
-1.0f,
1.0f
);
- device->unmap_buffer(config_buf);
- for (; e; e = e->next) {
- switch (e->type) {
- case Element::Type::label:
- vc += render_label((Label*)e, vc);
- break;
- }
- }
+ cbuffer.unmap(device);
+ cbuffer.update(ctx);
+
+ mesh.add_text(this, 10, 10, "Hello, world!", 0xff00ff);
Pipeline_Builder pb(s, device);
pb.begin_rp();
@@ -281,19 +373,10 @@ void UI::render(Arena* s, Texture_Id target) {
Blend_Factor::src_alpha,
Blend_Factor::inv_src_colour
);
- pb.cbuffer(shader_info.config_binding, config_buf);
+ pb.cbuffer(shader_info.config_binding, cbuffer.gpuonly);
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);
+ mesh.update_buffer(ctx);
+ mesh.draw(this, ctx, pip, pass);
}
diff --git a/ui.hpp b/ui.hpp
index c002fc9..4dc0dd9 100644
--- a/ui.hpp
+++ b/ui.hpp
@@ -6,36 +6,79 @@
struct Arena;
struct UI {
- struct Rect {
- int x, y, w, h;
+ struct Vertex {
+ float x, y, u, v, r, g, b, a;
};
- struct Element : Rect {
- enum class Type {
- label
- } type;
- Element* next;
- static int size(Type t);
+ struct Colour {
+ uint8_t r, g, b, a;
+ Colour(unsigned rgb, uint8_t a = 0xff);
+ float r_f() { return (float)r / 255.0f; };
+ float g_f() { return (float)g / 255.0f; };
+ float b_f() { return (float)b / 255.0f; };
+ float a_f() { return (float)a / 255.0f; };
};
- struct Label : Element {
- char* text;
- int len;
- int x, y;
+ struct Vertex_Buffer {
+ Staged_Buffer buf;
+ Buffer_Id indices;
+ int usage;
+
+ void init(Device* dev);
+ void init_indices(Device* dev);
+ void destroy(UI* ui);
+ void update_buffer(Context& ctx);
+
+ void add_quad(
+ UI* ui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float u0,
+ float v0,
+ float u1,
+ float v1,
+ Colour col
+ );
+ void add_rect(
+ UI* ui,
+ int x,
+ int y,
+ int w,
+ int h,
+ Colour col
+ );
+ void add_char(UI* ui, int x, int y, char ch, Colour col);
+ void add_text(
+ UI* ui,
+ int x,
+ int y,
+ const char* txt,
+ Colour col
+ );
+ void draw(
+ UI* ui,
+ Context& ctx,
+ Pipeline& pip,
+ Render_Pass& rp
+ );
+ Vertex_Buffer* next;
};
- struct Vertex {
- float x, y, u, v, r, g, b, a;
+ struct Rect {
+ int x, y, w, h;
};
- Arena* arena;
+ Heap* heap;
Device* device;
- Element* tree;
Texture_Id atlas;
Shader_Id shader;
Vertex_Format_Id vertex_format;
- Buffer_Id mesh, config_buf;
Sampler_Id sampler;
+ Staged_Buffer cbuffer;
+ Vertex_Buffer mesh;
+
struct UI_CBuffer {
m4f projection;
};
@@ -50,15 +93,15 @@ struct UI {
static UI* create(Device* dev, Arena* a, Shader_Id sh);
- Element* create_element(Element::Type t);
- Label* create_label(const char* t, int x, int y);
-
- void init(Device* dev, Arena* a, Texture_Id atlas, Shader_Id sh);
+ void init(
+ Device* dev,
+ Heap* h,
+ Texture_Id atlas,
+ Shader_Id sh
+ );
void destroy();
void update(Arena* s);
void render(Arena* s, Texture_Id target);
-
- int render_label(const Label* l, int off);
};
#endif