| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- /*
- * Copyright (c) 2012-2026 Daniele Bartolini et al.
- * SPDX-License-Identifier: MIT
- */
- #include "core/math/color4.inl"
- #include "core/math/constants.h"
- #include "core/math/matrix4x4.inl"
- #include "core/math/vector2.inl"
- #include "core/math/vector3.inl"
- #include "core/memory/memory.inl"
- #include "core/strings/string.inl"
- #include "core/strings/string_id.inl"
- #include "core/strings/utf8.h"
- #include "resource/font_resource.inl"
- #include "resource/material_resource.h"
- #include "resource/resource_manager.h"
- #include "world/gui.h"
- #include "world/material_manager.h"
- #include "world/shader_manager.h"
- #include <bgfx/bgfx.h>
- #include <float.h>
- namespace crown
- {
- static inline u32 depth_u32(f32 depth)
- {
- return u32(depth * 100.0f * 1000.0f);
- }
- GuiBuffer::GuiBuffer(ShaderManager &sm)
- : _shader_manager(&sm)
- , _num_vertices(0)
- , _num_indices(0)
- , _vertex_buffer()
- , _index_buffer()
- {
- }
- void *GuiBuffer::vertex_buffer_end()
- {
- return _vertex_buffer.data + _num_vertices*24;
- }
- void *GuiBuffer::index_buffer_end()
- {
- return _index_buffer.data + _num_indices*2;
- }
- void GuiBuffer::create()
- {
- _pos_tex_col.begin();
- _pos_tex_col.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);
- _pos_tex_col.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, true);
- _pos_tex_col.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
- _pos_tex_col.end();
- }
- void GuiBuffer::reset()
- {
- _num_vertices = 0;
- _num_indices = 0;
- bgfx::allocTransientVertexBuffer(&_vertex_buffer, 4096, _pos_tex_col);
- bgfx::allocTransientIndexBuffer(&_index_buffer, 6144);
- }
- void GuiBuffer::submit(u32 num_vertices, u32 num_indices, const Matrix4x4 &world, ShaderData &shader, u8 view, u32 depth)
- {
- bgfx::setVertexBuffer(0, &_vertex_buffer, _num_vertices, num_vertices);
- bgfx::setIndexBuffer(&_index_buffer, _num_indices, num_indices);
- bgfx::setTransform(to_float_ptr(world));
- bgfx::setState(shader.state);
- bgfx::submit(view, shader.program, depth);
- _num_vertices += num_vertices;
- _num_indices += num_indices;
- }
- void GuiBuffer::submit_with_material(u32 num_vertices, u32 num_indices, const Matrix4x4 &world, u8 view, u32 depth, Material *material)
- {
- bgfx::setVertexBuffer(0, &_vertex_buffer, _num_vertices, num_vertices);
- bgfx::setIndexBuffer(&_index_buffer, _num_indices, num_indices);
- bgfx::setTransform(to_float_ptr(world));
- material->bind(view, depth);
- _num_vertices += num_vertices;
- _num_indices += num_indices;
- }
- Gui::Gui(GuiBuffer &gb
- , ResourceManager &rm
- , ShaderManager &sm
- , MaterialManager &mm
- , ShaderData *shader
- , u8 view
- )
- : _marker(DEBUG_GUI_MARKER)
- , _buffer(&gb)
- , _resource_manager(&rm)
- , _shader_manager(&sm)
- , _material_manager(&mm)
- , _world(MATRIX4X4_IDENTITY)
- , _gui_shader(shader)
- , _view(view)
- {
- _node.next = NULL;
- _node.prev = NULL;
- }
- Gui::~Gui()
- {
- _marker = 0;
- }
- void Gui::move(const Vector2 &pos)
- {
- set_translation(_world, { pos.x, pos.y, 0 });
- }
- void Gui::triangle_3d(const Matrix4x4 &local_pose, const Vector3 &a, const Vector3 &b, const Vector3 &c, const Color4 &color, f32 depth)
- {
- VertexData *vd = (VertexData *)_buffer->vertex_buffer_end();
- vd[0].pos.x = a.x;
- vd[0].pos.y = a.y;
- vd[0].pos.z = a.z;
- vd[0].uv.x = 0.0f;
- vd[0].uv.y = 0.0f;
- vd[0].col = to_abgr(color);
- vd[1].pos.x = b.x;
- vd[1].pos.y = b.y;
- vd[1].pos.z = b.z;
- vd[1].uv.x = 1.0f;
- vd[1].uv.y = 0.0f;
- vd[1].col = to_abgr(color);
- vd[2].pos.x = c.x;
- vd[2].pos.y = c.y;
- vd[2].pos.z = c.z;
- vd[2].uv.x = 1.0f;
- vd[2].uv.y = 1.0f;
- vd[2].col = to_abgr(color);
- u16 *inds = (u16 *)_buffer->index_buffer_end();
- inds[0] = 0;
- inds[1] = 1;
- inds[2] = 2;
- _buffer->submit(3, 3, local_pose*_world, *_gui_shader, _view, depth_u32(depth));
- }
- void Gui::triangle(const Vector2 &a, const Vector2 &b, const Vector2 &c, const Color4 &color, f32 depth)
- {
- triangle_3d(MATRIX4X4_IDENTITY
- , { a.x, a.y, 0.0f }
- , { b.x, b.y, 0.0f }
- , { c.x, c.y, 0.0f }
- , color
- , depth
- );
- }
- void Gui::rect_3d(const Matrix4x4 &local_pose, const Vector3 &pos, const Vector2 &size, const Color4 &color, f32 depth)
- {
- VertexData *vd = (VertexData *)_buffer->vertex_buffer_end();
- vd[0].pos.x = pos.x;
- vd[0].pos.y = pos.y;
- vd[0].pos.z = pos.z;
- vd[0].uv.x = 0.0f;
- vd[0].uv.y = 1.0f;
- vd[0].col = to_abgr(color);
- vd[1].pos.x = pos.x + size.x;
- vd[1].pos.y = pos.y;
- vd[1].pos.z = pos.z;
- vd[1].uv.x = 1.0f;
- vd[1].uv.y = 1.0f;
- vd[1].col = to_abgr(color);
- vd[2].pos.x = pos.x + size.x;
- vd[2].pos.y = pos.y + size.y;
- vd[2].pos.z = pos.z;
- vd[2].uv.x = 1.0f;
- vd[2].uv.y = 0.0f;
- vd[2].col = to_abgr(color);
- vd[3].pos.x = pos.x;
- vd[3].pos.y = pos.y + size.y;
- vd[3].pos.z = pos.z;
- vd[3].uv.x = 0.0f;
- vd[3].uv.y = 0.0f;
- vd[3].col = to_abgr(color);
- u16 *inds = (u16 *)_buffer->index_buffer_end();
- inds[0] = 0;
- inds[1] = 1;
- inds[2] = 2;
- inds[3] = 0;
- inds[4] = 2;
- inds[5] = 3;
- _buffer->submit(4, 6, local_pose*_world, *_gui_shader, _view, depth_u32(depth));
- }
- void Gui::rect(const Vector3 &pos, const Vector2 &size, const Color4 &color)
- {
- rect_3d(MATRIX4X4_IDENTITY
- , { pos.x, pos.y, 0.0f }
- , size
- , color
- , pos.z
- );
- }
- void Gui::image_3d_uv(const Matrix4x4 &local_pose, const Vector3 &pos, const Vector2 &size, const Vector2 &uv0, const Vector2 &uv1, StringId64 material, const Color4 &color, f32 depth)
- {
- VertexData *vd = (VertexData *)_buffer->vertex_buffer_end();
- vd[0].pos.x = pos.x;
- vd[0].pos.y = pos.y;
- vd[0].pos.z = pos.z;
- vd[0].uv.x = uv0.x;
- vd[0].uv.y = uv1.y;
- vd[0].col = to_abgr(color);
- vd[1].pos.x = pos.x + size.x;
- vd[1].pos.y = pos.y;
- vd[1].pos.z = pos.z;
- vd[1].uv.x = uv1.x;
- vd[1].uv.y = uv1.y;
- vd[1].col = to_abgr(color);
- vd[2].pos.x = pos.x + size.x;
- vd[2].pos.y = pos.y + size.y;
- vd[2].pos.z = pos.z;
- vd[2].uv.x = uv1.x;
- vd[2].uv.y = uv0.y;
- vd[2].col = to_abgr(color);
- vd[3].pos.x = pos.x;
- vd[3].pos.y = pos.y + size.y;
- vd[3].pos.z = pos.z;
- vd[3].uv.x = uv0.x;
- vd[3].uv.y = uv0.y;
- vd[3].col = to_abgr(color);
- u16 *inds = (u16 *)_buffer->index_buffer_end();
- inds[0] = 0;
- inds[1] = 1;
- inds[2] = 2;
- inds[3] = 0;
- inds[4] = 2;
- inds[5] = 3;
- const MaterialResource *mr = (MaterialResource *)_resource_manager->get(RESOURCE_TYPE_MATERIAL, material);
- _material_manager->create_material(mr);
- _buffer->submit_with_material(4
- , 6
- , local_pose*_world
- , _view
- , depth_u32(depth)
- , _material_manager->get(mr)
- );
- }
- void Gui::image_uv(const Vector3 &pos, const Vector2 &size, const Vector2 &uv0, const Vector2 &uv1, StringId64 material, const Color4 &color)
- {
- image_3d_uv(MATRIX4X4_IDENTITY
- , { pos.x, pos.y, 0.0f }
- , size
- , uv0
- , uv1
- , material
- , color
- , pos.z
- );
- }
- void Gui::image_3d(const Matrix4x4 &local_pose, const Vector3 &pos, const Vector2 &size, StringId64 material, const Color4 &color, f32 depth)
- {
- image_3d_uv(local_pose
- , pos
- , size
- , VECTOR2_ZERO
- , VECTOR2_ONE
- , material
- , color
- , depth
- );
- }
- void Gui::image(const Vector3 &pos, const Vector2 &size, StringId64 material, const Color4 &color)
- {
- image_3d(MATRIX4X4_IDENTITY
- , { pos.x, pos.y, 0.0f }
- , size
- , material
- , color
- , pos.z
- );
- }
- void Gui::text_3d(const Matrix4x4 &local_pose, const Vector3 &pos, u32 font_size, const char *str, StringId64 font, StringId64 material, const Color4 &color, f32 depth)
- {
- const MaterialResource *mr = (MaterialResource *)_resource_manager->get(RESOURCE_TYPE_MATERIAL, material);
- _material_manager->create_material(mr);
- const FontResource *fr = (FontResource *)_resource_manager->get(RESOURCE_TYPE_FONT, font);
- const f32 scale = (f32)font_size / (f32)fr->font_size;
- VertexData *vd = (VertexData *)_buffer->vertex_buffer_end();
- u16 *id = (u16 *)_buffer->index_buffer_end();
- u32 num_vertices = 0;
- u32 num_indices = 0;
- u32 cp;
- u32 state = 0;
- f32 pen_x = 0.0f;
- f32 pen_y = 0.0f;
- const GlyphData deffault_glyph = {};
- for (const u8 *ch = (u8 *)str; *ch; ++ch) {
- if (utf8::decode(&state, &cp, *ch) != UTF8_ACCEPT)
- continue;
- if (cp == '\n') {
- pen_x = 0.0f;
- pen_y -= scale*fr->font_size;
- continue;
- } else if (cp == '\t') {
- pen_x += scale*font_size*4;
- continue;
- }
- const GlyphData *glyph = font_resource::glyph(fr, cp, &deffault_glyph);
- const f32 baseline = glyph->height - glyph->y_offset;
- const f32 x_offset = fsign(pen_x) * scale*glyph->x_offset;
- // Glyph position coords.
- const f32 x0 = pen_x + pos.x + x_offset;
- const f32 y0 = pen_y + pos.y - scale*baseline;
- const f32 x1 = x0 + scale*glyph->width;
- const f32 y1 = y0 + scale*glyph->height;
- pen_x += scale*glyph->x_advance;
- // Glyph atlas coords.
- const f32 u0 = glyph->x / fr->texture_size;
- const f32 v1 = glyph->y / fr->texture_size; // Upper-left char corner
- const f32 u1 = glyph->width / fr->texture_size + u0;
- const f32 v0 = glyph->height / fr->texture_size + v1; // Bottom-left char corner
- const u32 abgr = to_abgr(color);
- // Fill vertex buffer.
- vd[0].pos.x = x0;
- vd[0].pos.y = y0;
- vd[0].pos.z = pos.z;
- vd[0].uv.x = u0;
- vd[0].uv.y = v0;
- vd[0].col = abgr;
- vd[1].pos.x = x1;
- vd[1].pos.y = y0;
- vd[1].pos.z = pos.z;
- vd[1].uv.x = u1;
- vd[1].uv.y = v0;
- vd[1].col = abgr;
- vd[2].pos.x = x1;
- vd[2].pos.y = y1;
- vd[2].pos.z = pos.z;
- vd[2].uv.x = u1;
- vd[2].uv.y = v1;
- vd[2].col = abgr;
- vd[3].pos.x = x0;
- vd[3].pos.y = y1;
- vd[3].pos.z = pos.z;
- vd[3].uv.x = u0;
- vd[3].uv.y = v1;
- vd[3].col = abgr;
- // Fill index buffer.
- id[0] = num_vertices + 0;
- id[1] = num_vertices + 1;
- id[2] = num_vertices + 2;
- id[3] = num_vertices + 0;
- id[4] = num_vertices + 2;
- id[5] = num_vertices + 3;
- vd += 4;
- id += 6;
- num_vertices += 4;
- num_indices += 6;
- }
- _buffer->submit_with_material(num_vertices
- , num_indices
- , local_pose*_world
- , _view
- , depth_u32(depth)
- , _material_manager->get(mr)
- );
- }
- void Gui::text(const Vector3 &pos, u32 font_size, const char *str, StringId64 font, StringId64 material, const Color4 &color)
- {
- const MaterialResource *mr = (MaterialResource *)_resource_manager->get(RESOURCE_TYPE_MATERIAL, material);
- _material_manager->create_material(mr);
- const FontResource *fr = (FontResource *)_resource_manager->get(RESOURCE_TYPE_FONT, font);
- const f32 scale = (f32)font_size / (f32)fr->font_size;
- VertexData *vd = (VertexData *)_buffer->vertex_buffer_end();
- u16 *id = (u16 *)_buffer->index_buffer_end();
- u32 num_vertices = 0;
- u32 num_indices = 0;
- u32 cp;
- u32 state = 0;
- f32 pen_x = 0.0f;
- f32 pen_y = 0.0f;
- const GlyphData deffault_glyph = {};
- for (const u8 *ch = (u8 *)str; *ch; ++ch) {
- if (utf8::decode(&state, &cp, *ch) != UTF8_ACCEPT)
- continue;
- if (cp == '\n') {
- pen_x = 0.0f;
- pen_y -= scale*fr->font_size;
- continue;
- } else if (cp == '\t') {
- pen_x += scale*font_size*4;
- continue;
- }
- const GlyphData *glyph = font_resource::glyph(fr, cp, &deffault_glyph);
- const f32 baseline = glyph->height - glyph->y_offset;
- const f32 x_offset = fsign(pen_x) * scale*glyph->x_offset;
- // Glyph position coords.
- const f32 x0 = pen_x + pos.x + x_offset;
- const f32 y0 = pen_y + pos.y - scale*baseline;
- const f32 x1 = fround(x0 + scale*glyph->width);
- const f32 y1 = fround(y0 + scale*glyph->height);
- pen_x += scale*glyph->x_advance;
- // Glyph atlas coords.
- const f32 u0 = glyph->x / fr->texture_size;
- const f32 v1 = glyph->y / fr->texture_size; // Upper-left char corner
- const f32 u1 = glyph->width / fr->texture_size + u0;
- const f32 v0 = glyph->height / fr->texture_size + v1; // Bottom-left char corner
- const u32 abgr = to_abgr(color);
- // Fill vertex buffer.
- vd[0].pos.x = x0;
- vd[0].pos.y = y0;
- vd[0].pos.z = 0.0f;
- vd[0].uv.x = u0;
- vd[0].uv.y = v0;
- vd[0].col = abgr;
- vd[1].pos.x = x1;
- vd[1].pos.y = y0;
- vd[1].pos.z = 0.0f;
- vd[1].uv.x = u1;
- vd[1].uv.y = v0;
- vd[1].col = abgr;
- vd[2].pos.x = x1;
- vd[2].pos.y = y1;
- vd[2].pos.z = 0.0f;
- vd[2].uv.x = u1;
- vd[2].uv.y = v1;
- vd[2].col = abgr;
- vd[3].pos.x = x0;
- vd[3].pos.y = y1;
- vd[3].pos.z = 0.0f;
- vd[3].uv.x = u0;
- vd[3].uv.y = v1;
- vd[3].col = abgr;
- // Fill index buffer.
- id[0] = num_vertices + 0;
- id[1] = num_vertices + 1;
- id[2] = num_vertices + 2;
- id[3] = num_vertices + 0;
- id[4] = num_vertices + 2;
- id[5] = num_vertices + 3;
- vd += 4;
- id += 6;
- num_vertices += 4;
- num_indices += 6;
- }
- _buffer->submit_with_material(num_vertices
- , num_indices
- , _world
- , _view
- , depth_u32(pos.z)
- , _material_manager->get(mr)
- );
- }
- Vector2 Gui::text_extents(const u32 font_size, const char *str, StringId64 font)
- {
- const FontResource *fr = (FontResource *)_resource_manager->get(RESOURCE_TYPE_FONT, font);
- const f32 scale = (f32)font_size / (f32)fr->font_size;
- u32 cp;
- u32 state = 0;
- const GlyphData deffault_glyph = {};
- f32 pen_x = 0.0f;
- f32 pen_y = 0.0f;
- Vector2 box_min = { FLT_MAX, FLT_MAX };
- Vector2 box_max = { -FLT_MAX, -FLT_MAX };
- for (const u8 *ch = (u8 *)str; *ch; ++ch) {
- if (utf8::decode(&state, &cp, *ch) != UTF8_ACCEPT)
- continue;
- if (cp == '\n') {
- pen_x = 0.0f;
- pen_y -= scale*fr->font_size;
- continue;
- } else if (cp == '\t') {
- pen_x += scale*font_size*4;
- continue;
- }
- const GlyphData *glyph = font_resource::glyph(fr, cp, &deffault_glyph);
- const f32 baseline = glyph->height - glyph->y_offset;
- const f32 x_offset = fsign(pen_x) * scale*glyph->x_offset;
- // Glyph position coords.
- const f32 x0 = pen_x + x_offset;
- const f32 y0 = pen_y - scale*baseline;
- const f32 x1 = fround(x0 + scale*glyph->width);
- const f32 y1 = fround(y0 + scale*glyph->height);
- box_min = min(box_min, { x0, y0 });
- box_max = max(box_max, { x1, y1 });
- pen_x += scale*glyph->x_advance;
- }
- // Avoid returning funny extents empty or malformed strings.
- box_min = min(box_min, VECTOR2_ZERO);
- box_max = max(box_max, VECTOR2_ZERO);
- return box_max - box_min;
- }
- Material *Gui::material(ResourceId material_resource)
- {
- const MaterialResource *mr = (MaterialResource *)_resource_manager->get(RESOURCE_TYPE_MATERIAL, material_resource);
- return _material_manager->get(mr);
- }
- namespace gui
- {
- Gui *create_screen_gui(Allocator &allocator
- , GuiBuffer &buffer
- , ResourceManager &resource_manager
- , ShaderManager &shader_manager
- , MaterialManager &material_manager
- , ShaderData *shader
- )
- {
- Gui *gui = CE_NEW(allocator, Gui)(buffer
- , resource_manager
- , shader_manager
- , material_manager
- , shader
- , View::SCREEN_GUI
- );
- return gui;
- }
- Gui *create_world_gui(Allocator &allocator
- , GuiBuffer &buffer
- , ResourceManager &resource_manager
- , ShaderManager &shader_manager
- , MaterialManager &material_manager
- , ShaderData *shader
- )
- {
- Gui *gui = CE_NEW(allocator, Gui)(buffer
- , resource_manager
- , shader_manager
- , material_manager
- , shader
- , View::WORLD_GUI
- );
- return gui;
- }
- } // namespace gui
- } // namespace crown
|