Immediate gui
This commit is contained in:
parent
dfe2b8a8c8
commit
53f64b8513
@ -91,8 +91,6 @@ set(CLIENT_ONLY_SOURCES
|
||||
"src/gfx/buffer_object.cpp"
|
||||
"src/gfx/buffer_object.hpp"
|
||||
"src/gfx/draw_list.hpp"
|
||||
"src/gfx/font.hpp"
|
||||
"src/gfx/font.cpp"
|
||||
"src/gfx/frustum.hpp"
|
||||
"src/gfx/frustum.cpp"
|
||||
"src/gfx/hud.hpp"
|
||||
@ -104,13 +102,15 @@ set(CLIENT_ONLY_SOURCES
|
||||
"src/gfx/shader.hpp"
|
||||
"src/gfx/shader.cpp"
|
||||
"src/gfx/surface.hpp"
|
||||
"src/gfx/text.hpp"
|
||||
"src/gfx/text.cpp"
|
||||
"src/gfx/texture.cpp"
|
||||
"src/gfx/texture.hpp"
|
||||
"src/gfx/uniform_buffer.hpp"
|
||||
"src/gfx/vertex_array.cpp"
|
||||
"src/gfx/vertex_array.hpp"
|
||||
"src/gui/context.hpp"
|
||||
"src/gui/context.cpp"
|
||||
"src/gui/font.hpp"
|
||||
"src/gui/font.cpp"
|
||||
"src/utils/files.cpp"
|
||||
)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#ifdef CLIENT
|
||||
#include "audio/sound.hpp"
|
||||
#include "gfx/texture.hpp"
|
||||
#include "gfx/font.hpp"
|
||||
#include "gui/font.hpp"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
@ -61,10 +61,10 @@ protected:
|
||||
PtrType Load(const std::string& key) override { return audio::Sound::LoadFromFile(key); }
|
||||
};
|
||||
|
||||
class FontCache final : public Cache<gfx::Font>
|
||||
class FontCache final : public Cache<gui::Font>
|
||||
{
|
||||
protected:
|
||||
PtrType Load(const std::string& key) override { return gfx::Font::LoadFromFile(key); }
|
||||
PtrType Load(const std::string& key) override { return gui::Font::LoadFromFile(key); }
|
||||
};
|
||||
#endif // CLIENT
|
||||
|
||||
@ -120,7 +120,7 @@ public:
|
||||
return sound_cache_.Get(filename);
|
||||
}
|
||||
|
||||
static std::shared_ptr<const gfx::Font> GetFont(const std::string& filename)
|
||||
static std::shared_ptr<const gui::Font> GetFont(const std::string& filename)
|
||||
{
|
||||
return font_cache_.Get(filename);
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
#include "assets/cache.hpp"
|
||||
#include "gameview/worldview.hpp"
|
||||
|
||||
App::App()
|
||||
App::App() :
|
||||
gui_(dlist_, assets::CacheManager::GetFont("data/comic32.font"))
|
||||
{
|
||||
std::cout << "Initializing App..." << std::endl;
|
||||
|
||||
@ -17,9 +18,6 @@ App::App()
|
||||
audiomaster_.SetMasterVolume(2.0f);
|
||||
#endif
|
||||
|
||||
font_ = assets::CacheManager::GetFont("data/comic32.font");
|
||||
|
||||
InitChat();
|
||||
AddChatMessage("Test!");
|
||||
}
|
||||
|
||||
@ -76,16 +74,19 @@ void App::Frame()
|
||||
params.screen_width = viewport_size_.x;
|
||||
params.screen_height = viewport_size_.y;
|
||||
|
||||
gui_.Begin();
|
||||
|
||||
const game::view::WorldView* world;
|
||||
if (session_)
|
||||
{
|
||||
session_->Draw(dlist_, params);
|
||||
session_->Draw(dlist_, params, gui_);
|
||||
}
|
||||
|
||||
// draw chat
|
||||
UpdateChat();
|
||||
DrawChat(dlist_);
|
||||
DrawChat();
|
||||
|
||||
gui_.Render();
|
||||
renderer_.DrawList(dlist_, params);
|
||||
}
|
||||
|
||||
@ -144,8 +145,7 @@ void App::AddChatMessage(const std::string& text)
|
||||
{
|
||||
auto& ch = chat_.emplace_back();
|
||||
ch.timeout = time_ + 10.0f;
|
||||
ch.text = std::make_unique<gfx::Text>(font_, 0xFF'FF'FF'FF);
|
||||
ch.text->SetText(text);
|
||||
ch.text = text;
|
||||
UpdateChat();
|
||||
}
|
||||
|
||||
@ -165,38 +165,21 @@ void App::SendInput(game::PlayerInputType type, bool enable)
|
||||
msg.Write(val);
|
||||
}
|
||||
|
||||
void App::InitChat()
|
||||
{
|
||||
chatpos_.resize(20); // max messages on screen
|
||||
const float chat_scale = 1.0f;
|
||||
for (size_t i = 0; i < chatpos_.size(); ++i)
|
||||
{
|
||||
auto& hudp = chatpos_[i];
|
||||
hudp.pos.y = (i+1) * font_->GetLineHeight() * chat_scale;
|
||||
hudp.scale.x = chat_scale;
|
||||
hudp.scale.y = -chat_scale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void App::UpdateChat()
|
||||
{
|
||||
// remove expired or over the limit messages
|
||||
while (!chat_.empty() && (chat_.size() > chatpos_.size() ||chat_[0].timeout < time_))
|
||||
while (!chat_.empty() && (chat_.size() > 20 ||chat_[0].timeout < time_))
|
||||
{
|
||||
chat_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void App::DrawChat(gfx::DrawList& dlist)
|
||||
void App::DrawChat()
|
||||
{
|
||||
for (size_t i = 0; i < chat_.size(); ++i)
|
||||
{
|
||||
const auto& va = chat_[i].text->GetVA();
|
||||
glm::vec2 pos(10.0f, static_cast<float>(i) * gui_.GetFont()->GetLineHeight() + 10.0f);
|
||||
|
||||
if (va.GetNumIndices() < 1)
|
||||
continue;
|
||||
|
||||
float t_rem = chat_[i].timeout - time_;
|
||||
const float fade = 1.0f;
|
||||
if (t_rem < fade)
|
||||
@ -204,11 +187,7 @@ void App::DrawChat(gfx::DrawList& dlist)
|
||||
chat_[i].color.a = t_rem / fade;
|
||||
}
|
||||
|
||||
gfx::DrawHudCmd cmd;
|
||||
cmd.pos = &chatpos_[i];
|
||||
cmd.texture = chat_[i].text->GetFont()->GetTexture().get();
|
||||
cmd.va = &va;
|
||||
cmd.color = &chat_[i].color;
|
||||
dlist.AddHUD(cmd);
|
||||
uint32_t color = glm::packUnorm4x8(chat_[i].color);
|
||||
gui_.DrawText(chat_[i].text, pos, color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
|
||||
#include "game/player_input.hpp"
|
||||
#include "gfx/renderer.hpp"
|
||||
#include "gfx/text.hpp"
|
||||
#include "gui/font.hpp"
|
||||
#include "gui/context.hpp"
|
||||
#include "audio/master.hpp"
|
||||
#include "net/msg_producer.hpp"
|
||||
#include "net/inmessage.hpp"
|
||||
@ -14,14 +15,13 @@
|
||||
|
||||
struct ChatMessage
|
||||
{
|
||||
std::unique_ptr<gfx::Text> text;
|
||||
std::string text;
|
||||
float timeout = 0.0f;
|
||||
glm::vec4 color = glm::vec4(1.0f);
|
||||
};
|
||||
|
||||
class App : public net::MsgProducer
|
||||
{
|
||||
|
||||
public:
|
||||
App();
|
||||
|
||||
@ -49,9 +49,8 @@ public:
|
||||
private:
|
||||
void SendInput(game::PlayerInputType type, bool enable);
|
||||
|
||||
void InitChat();
|
||||
void UpdateChat();
|
||||
void DrawChat(gfx::DrawList& dlist);
|
||||
void DrawChat();
|
||||
|
||||
private:
|
||||
float time_ = 0.0f;
|
||||
@ -59,19 +58,16 @@ private:
|
||||
game::PlayerInputFlags input_ = 0;
|
||||
game::PlayerInputFlags prev_input_ = 0;
|
||||
|
||||
|
||||
float prev_time_ = 0.0f;
|
||||
float delta_time_ = 0.0f;
|
||||
|
||||
gfx::Renderer renderer_;
|
||||
gfx::DrawList dlist_;
|
||||
gui::Context gui_;
|
||||
|
||||
audio::Master audiomaster_;
|
||||
|
||||
std::unique_ptr<game::view::ClientSession> session_;
|
||||
|
||||
std::shared_ptr<const gfx::Font> font_;
|
||||
|
||||
std::deque<ChatMessage> chat_;
|
||||
std::vector<gfx::HudPosition> chatpos_;
|
||||
};
|
||||
|
||||
@ -73,11 +73,11 @@ void game::view::ClientSession::Update(const UpdateInfo& info)
|
||||
}
|
||||
}
|
||||
|
||||
void game::view::ClientSession::Draw(gfx::DrawList& dlist, gfx::DrawListParams& params)
|
||||
void game::view::ClientSession::Draw(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui)
|
||||
{
|
||||
if (world_)
|
||||
{
|
||||
DrawWorld(dlist, params);
|
||||
DrawWorld(dlist, params, gui);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ bool game::view::ClientSession::ProcessChatMsg(net::InMessage& msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params)
|
||||
void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui)
|
||||
{
|
||||
// glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f,
|
||||
// 0.0f, 1.0f));
|
||||
@ -164,8 +164,7 @@ void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListPar
|
||||
|
||||
// glm::mat4 fake_view_proj = glm::perspective(glm::radians(30.0f), aspect, 0.1f, 3000.0f) * view;
|
||||
|
||||
game::view::DrawArgs draw_args(dlist, params.view_proj, eye, glm::ivec2(params.screen_width, params.screen_height),
|
||||
500.0f);
|
||||
game::view::DrawArgs draw_args(dlist, gui, params.view_proj, eye, glm::ivec2(params.screen_width, params.screen_height), 500.0f);
|
||||
world_->Draw(draw_args);
|
||||
|
||||
glm::mat4 camera_world = glm::inverse(view);
|
||||
|
||||
@ -25,7 +25,7 @@ public:
|
||||
void ProcessMouseMove(float delta_yaw, float delta_pitch);
|
||||
|
||||
void Update(const UpdateInfo& info);
|
||||
void Draw(gfx::DrawList& dlist, gfx::DrawListParams& params);
|
||||
void Draw(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui);
|
||||
|
||||
const WorldView* GetWorld() const { return world_.get(); }
|
||||
|
||||
@ -39,7 +39,7 @@ private:
|
||||
bool ProcessCameraMsg(net::InMessage& msg);
|
||||
bool ProcessChatMsg(net::InMessage& msg);
|
||||
|
||||
void DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params);
|
||||
void DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui);
|
||||
void SendViewAngles(float time);
|
||||
|
||||
private:
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "gfx/draw_list.hpp"
|
||||
#include "gfx/frustum.hpp"
|
||||
#include "gui/context.hpp"
|
||||
|
||||
namespace game::view
|
||||
{
|
||||
@ -9,6 +10,7 @@ namespace game::view
|
||||
struct DrawArgs
|
||||
{
|
||||
gfx::DrawList& dlist;
|
||||
gui::Context& gui;
|
||||
|
||||
const glm::mat4 view_proj;
|
||||
const glm::vec3 eye;
|
||||
@ -16,8 +18,8 @@ struct DrawArgs
|
||||
const glm::ivec2 screen_size;
|
||||
const float render_distance;
|
||||
|
||||
DrawArgs(gfx::DrawList& dlist, const glm::mat4& view_proj, const glm::vec3& eye, const glm::ivec2& screen_size, float render_distance)
|
||||
: dlist(dlist), view_proj(view_proj), eye(eye), frustum(view_proj), screen_size(screen_size), render_distance(render_distance)
|
||||
DrawArgs(gfx::DrawList& dlist, gui::Context& gui, const glm::mat4& view_proj, const glm::vec3& eye, const glm::ivec2& screen_size, float render_distance)
|
||||
: dlist(dlist), gui(gui), view_proj(view_proj), eye(eye), frustum(view_proj), screen_size(screen_size), render_distance(render_distance)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -7,8 +7,7 @@
|
||||
|
||||
game::view::EntityView::EntityView(WorldView& world, net::InMessage& msg) :
|
||||
world_(world),
|
||||
audioplayer_(world_.GetAudioMaster()),
|
||||
nametag_text_(assets::CacheManager::GetFont("data/comic32.font"), 0xFFFFFFFF)
|
||||
audioplayer_(world_.GetAudioMaster())
|
||||
{
|
||||
// read nametag and attachment info
|
||||
if (!ReadNametag(msg) || !ReadAttach(msg))
|
||||
@ -80,7 +79,6 @@ bool game::view::EntityView::ReadNametag(net::InMessage& msg)
|
||||
return false;
|
||||
|
||||
nametag_ = nametag;
|
||||
nametag_text_.SetText(nametag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -125,24 +123,14 @@ void game::view::EntityView::DrawNametag(const DrawArgs& args)
|
||||
if (ndc_pos.z < -1.0f || ndc_pos.z > 1.0f)
|
||||
return; // behind camera
|
||||
|
||||
nametag_pos_.anchor.x = ndc_pos.x * 0.5f + 0.5f;
|
||||
nametag_pos_.anchor.y = 1.0f - (ndc_pos.y * 0.5f + 0.5f); // flip y
|
||||
glm::vec2 anchor = ndc_pos * 0.5f + 0.5f;
|
||||
anchor.y = 1.0f - anchor.y;
|
||||
anchor *= args.screen_size;
|
||||
|
||||
// center
|
||||
float scale = 0.7f;
|
||||
nametag_pos_.scale = glm::vec2(scale, -scale);
|
||||
nametag_pos_.pos = nametag_text_.GetSize() * glm::vec2(-0.5f, -1.0f) * scale;
|
||||
|
||||
// static const glm::vec4 nametag_color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
gfx::DrawHudCmd hudcmd;
|
||||
hudcmd.va = &nametag_text_.GetVA();
|
||||
hudcmd.texture = nametag_text_.GetFont()->GetTexture().get();
|
||||
hudcmd.pos = &nametag_pos_;
|
||||
// hudcmd.color = &nametag_color;
|
||||
args.dlist.AddHUD(hudcmd);
|
||||
// std::cout << "at position: " << root_.local.position.x << ", " << root_.local.position.y << ", " << root_.local.position.z << std::endl;
|
||||
glm::vec2 pos = anchor + args.gui.MeasureText(nametag_) * glm::vec2(-0.5f, -1.0f) * scale;
|
||||
|
||||
args.gui.DrawText(nametag_, pos, 0xFFFFFFFF, scale);
|
||||
}
|
||||
|
||||
void game::view::EntityView::DrawAxes(const DrawArgs& args)
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include "audio/player.hpp"
|
||||
#include "draw_args.hpp"
|
||||
#include "game/transform_node.hpp"
|
||||
#include "gfx/text.hpp"
|
||||
|
||||
#include "net/defs.hpp"
|
||||
#include "net/inmessage.hpp"
|
||||
@ -72,8 +71,6 @@ protected:
|
||||
|
||||
private:
|
||||
std::string nametag_;
|
||||
gfx::Text nametag_text_;
|
||||
gfx::HudPosition nametag_pos_;
|
||||
|
||||
net::EntNum parentnum_ = 0;
|
||||
float upd_time_ = 0.0f;
|
||||
|
||||
@ -43,6 +43,8 @@ struct DrawHudCmd
|
||||
const Texture* texture = nullptr;
|
||||
const HudPosition* pos = nullptr;
|
||||
const glm::vec4* color = nullptr;
|
||||
size_t first = 0;
|
||||
size_t count = 0;
|
||||
};
|
||||
|
||||
struct DrawList
|
||||
|
||||
@ -150,8 +150,8 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
return a.dist > b.dist; // do not optimize blended, sort by distance instead
|
||||
}
|
||||
|
||||
if (auto cmp = sa <=> sb; cmp != 0)
|
||||
return cmp < 0;
|
||||
if (sa == sb)
|
||||
return false;
|
||||
|
||||
if (auto cmp = sa->texture <=> sb->texture; cmp != 0)
|
||||
return cmp < 0;
|
||||
@ -159,6 +159,9 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
if (auto cmp = sa->va.get() <=> sb->va.get(); cmp != 0)
|
||||
return cmp < 0;
|
||||
|
||||
if (auto cmp = sa <=> sb; cmp != 0)
|
||||
return cmp < 0;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -462,6 +465,9 @@ void gfx::Renderer::DrawHudList(std::span<DrawHudCmd> queue, const DrawListParam
|
||||
last_vao = cmd.va;
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(cmd.va->GetNumIndices()), GL_UNSIGNED_INT, NULL);
|
||||
size_t first = cmd.first * 3;
|
||||
size_t count = cmd.count ? cmd.count * 3 : cmd.va->GetNumIndices();
|
||||
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(count), GL_UNSIGNED_INT, (void*)(first * sizeof(GLuint)));
|
||||
}
|
||||
}
|
||||
|
||||
175
src/gfx/text.cpp
175
src/gfx/text.cpp
@ -1,175 +0,0 @@
|
||||
#include "text.hpp"
|
||||
|
||||
#include "utils/bufferput.hpp"
|
||||
|
||||
gfx::Text::Text(std::shared_ptr<const Font> font, uint32_t color)
|
||||
: font_(std::move(font)), va_(VA_POSITION | VA_UV | VA_COLOR, VF_CREATE_EBO | VF_DYNAMIC), color_(color)
|
||||
{
|
||||
}
|
||||
|
||||
static uint32_t DecodeUTF8Codepoint(const char*& p)
|
||||
{
|
||||
if (!*p)
|
||||
return 0;
|
||||
|
||||
if ((*p & 0b10000000) == 0)
|
||||
{ // 1-byte sequence
|
||||
return *p++;
|
||||
}
|
||||
|
||||
uint32_t codepoint = 0;
|
||||
|
||||
if ((*p & 0b11100000) == 0b11000000)
|
||||
{ // 2-byte seq
|
||||
codepoint = (*p++ & 0b00011111) << 6;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
else if ((*p & 0b11110000) == 0b11100000)
|
||||
{ // 3-byte seq
|
||||
codepoint = (*p++ & 0b00001111) << 12;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 6;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
else if ((*p & 0b11111000) == 0b11110000)
|
||||
{ // 4-byte seq
|
||||
codepoint = (*p++ & 0b00000111) << 18;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 12;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 6;
|
||||
if (!*p)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
|
||||
struct TextVertex
|
||||
{
|
||||
glm::vec3 pos;
|
||||
uint32_t color;
|
||||
glm::vec2 uv;
|
||||
};
|
||||
|
||||
static void PutVertex(std::vector<TextVertex>& buf, const glm::vec3 pos, const glm::vec2& uv, uint32_t color)
|
||||
{
|
||||
//BufferPut(buf, pos);
|
||||
//BufferPut(buf, color);
|
||||
//BufferPut(buf, uv);
|
||||
buf.emplace_back(TextVertex{pos, color, uv});
|
||||
}
|
||||
|
||||
void gfx::Text::SetText(const char* text)
|
||||
{
|
||||
static std::vector<TextVertex> vertices;
|
||||
static std::vector<uint32_t> indices;
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
float space_size = font_->GetLineHeight() * 0.3f;
|
||||
|
||||
const float line_height = font_->GetLineHeight();
|
||||
size_ = glm::vec2(0.0f);
|
||||
glm::vec2 cursor(0.0f);
|
||||
|
||||
uint32_t cp = 0;
|
||||
const char* p = text;
|
||||
|
||||
uint32_t color = color_;
|
||||
|
||||
|
||||
while (cp = DecodeUTF8Codepoint(p))
|
||||
{
|
||||
if (cp == ' ')
|
||||
{
|
||||
cursor.x += space_size; // Move cursor for space
|
||||
continue;
|
||||
}
|
||||
else if (cp == '\n')
|
||||
{
|
||||
cursor.x = 0.0f;
|
||||
cursor.y += line_height;
|
||||
continue;
|
||||
}
|
||||
else if (cp == '^')
|
||||
{
|
||||
if (!(cp = DecodeUTF8Codepoint(p)))
|
||||
break;
|
||||
|
||||
if (cp == 'r') // reset color
|
||||
{
|
||||
color = color_;
|
||||
continue;
|
||||
}
|
||||
|
||||
color = 0;
|
||||
|
||||
// parse color
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
color >>= 8;
|
||||
uint32_t ch;
|
||||
if (cp >= '0' && cp <= '9')
|
||||
ch = cp - '0';
|
||||
else if (cp >= 'a' && cp <= 'f')
|
||||
ch = cp - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
color |= (ch << 16);
|
||||
color |= (ch << 20);
|
||||
|
||||
if (!(cp = DecodeUTF8Codepoint(p)))
|
||||
break;
|
||||
}
|
||||
|
||||
color |= 0xFF000000; // alpha=1
|
||||
|
||||
//if (cp != ';')
|
||||
// break;
|
||||
|
||||
//continue;
|
||||
}
|
||||
|
||||
const FontGlyphData* glyph = font_->GetCodepointGlyph(cp);
|
||||
|
||||
if (!glyph)
|
||||
continue; // Dont even have "missing" glyph, font is shit
|
||||
|
||||
glm::vec2 p0 = cursor + glyph->offset;
|
||||
glm::vec2 p1 = p0 + glyph->size;
|
||||
|
||||
uint32_t base_index = vertices.size();
|
||||
|
||||
PutVertex(vertices, glm::vec3(p0.x, -p0.y, 0.0f), glyph->uv0, color);
|
||||
PutVertex(vertices, glm::vec3(p1.x, -p0.y, 0.0f), glm::vec2(glyph->uv1.x, glyph->uv0.y), color);
|
||||
PutVertex(vertices, glm::vec3(p1.x, -p1.y, 0.0f), glyph->uv1, color);
|
||||
PutVertex(vertices, glm::vec3(p0.x, -p1.y, 0.0f), glm::vec2(glyph->uv0.x, glyph->uv1.y), color);
|
||||
|
||||
indices.push_back(base_index + 0);
|
||||
indices.push_back(base_index + 1);
|
||||
indices.push_back(base_index + 2);
|
||||
indices.push_back(base_index + 0);
|
||||
indices.push_back(base_index + 2);
|
||||
indices.push_back(base_index + 3);
|
||||
|
||||
cursor.x += glyph->advance;
|
||||
|
||||
size_.x = glm::max(size_.x, cursor.x);
|
||||
}
|
||||
|
||||
size_.y = cursor.y + line_height;
|
||||
|
||||
va_.SetVBOData(vertices.data(), vertices.size() * sizeof(TextVertex));
|
||||
va_.SetIndices(indices.data(), indices.size());
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "font.hpp"
|
||||
#include "vertex_array.hpp"
|
||||
|
||||
namespace gfx
|
||||
{
|
||||
|
||||
class Text
|
||||
{
|
||||
public:
|
||||
Text(std::shared_ptr<const Font> font, uint32_t color);
|
||||
|
||||
void SetText(const char* text);
|
||||
void SetText(const std::string& text) { SetText(text.c_str()); }
|
||||
|
||||
const std::shared_ptr<const Font>& GetFont() const { return font_; }
|
||||
const VertexArray& GetVA() const { return va_; }
|
||||
const glm::vec2& GetSize() const { return size_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<const Font> font_;
|
||||
VertexArray va_;
|
||||
uint32_t color_;
|
||||
glm::vec2 size_; // size of the text in pixels
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
249
src/gui/context.cpp
Normal file
249
src/gui/context.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
#include "context.hpp"
|
||||
|
||||
gui::Context::Context(gfx::DrawList& dlist, std::shared_ptr<const Font> default_font) :
|
||||
dlist_(dlist),
|
||||
font_(std::move(default_font)),
|
||||
va_(gfx::VA_POSITION | gfx::VA_UV | gfx::VA_COLOR, gfx::VF_CREATE_EBO | gfx::VF_DYNAMIC)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gui::Context::Begin()
|
||||
{
|
||||
vertices_.clear();
|
||||
indices_.clear();
|
||||
ranges_.clear();
|
||||
}
|
||||
|
||||
static uint32_t DecodeUTF8Codepoint(const char*& p, const char* end)
|
||||
{
|
||||
if (p == end)
|
||||
return 0;
|
||||
|
||||
if ((*p & 0b10000000) == 0)
|
||||
{ // 1-byte sequence
|
||||
return *p++;
|
||||
}
|
||||
|
||||
uint32_t codepoint = 0;
|
||||
|
||||
if ((*p & 0b11100000) == 0b11000000)
|
||||
{ // 2-byte seq
|
||||
codepoint = (*p++ & 0b00011111) << 6;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
else if ((*p & 0b11110000) == 0b11100000)
|
||||
{ // 3-byte seq
|
||||
codepoint = (*p++ & 0b00001111) << 12;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 6;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
else if ((*p & 0b11111000) == 0b11110000)
|
||||
{ // 4-byte seq
|
||||
codepoint = (*p++ & 0b00000111) << 18;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 12;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111) << 6;
|
||||
if (p == end)
|
||||
return 0;
|
||||
codepoint |= (*p++ & 0b00111111);
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
glm::vec2 gui::Context::MeasureText(std::string_view text)
|
||||
{
|
||||
glm::vec2 size(0.0f);
|
||||
|
||||
const char* p = text.data();
|
||||
const char* end = p + text.size();
|
||||
|
||||
if (p == end) // empty string
|
||||
return size;
|
||||
|
||||
uint32_t cp = 0;
|
||||
const float line_height = font_->GetLineHeight();
|
||||
float space_size = line_height * 0.3f;
|
||||
|
||||
glm::vec2 cursor(0.0f);
|
||||
|
||||
while (cp = DecodeUTF8Codepoint(p, end))
|
||||
{
|
||||
if (cp == ' ')
|
||||
{
|
||||
cursor.x += space_size; // Move cursor for space
|
||||
continue;
|
||||
}
|
||||
else if (cp == '\n')
|
||||
{
|
||||
cursor.x = 0.0f;
|
||||
cursor.y += line_height;
|
||||
continue;
|
||||
}
|
||||
else if (cp == '^')
|
||||
{
|
||||
if (!(cp = DecodeUTF8Codepoint(p, end)))
|
||||
break;
|
||||
|
||||
if (cp == 'r')
|
||||
continue;
|
||||
|
||||
// parse color
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
if (!(cp = DecodeUTF8Codepoint(p, end)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const FontGlyphData* glyph = font_->GetCodepointGlyph(cp);
|
||||
|
||||
if (!glyph)
|
||||
continue; // Dont even have "missing" glyph, font is shit
|
||||
|
||||
cursor.x += glyph->advance;
|
||||
size.x = glm::max(size.x, cursor.x);
|
||||
}
|
||||
|
||||
size.y = cursor.y + line_height;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void gui::Context::DrawText(std::string_view text, const glm::vec2& pos, uint32_t color, float scale)
|
||||
{
|
||||
const char* p = text.data();
|
||||
const char* end = p + text.size();
|
||||
|
||||
if (p == end) // empty string
|
||||
return;
|
||||
|
||||
BeginTexture(font_->GetTexture().get());
|
||||
|
||||
uint32_t cp = 0;
|
||||
const float line_height = font_->GetLineHeight();
|
||||
float space_size = line_height * 0.3f;
|
||||
|
||||
glm::vec2 cursor = pos;
|
||||
|
||||
uint32_t curr_color = color;
|
||||
|
||||
while (cp = DecodeUTF8Codepoint(p, end))
|
||||
{
|
||||
if (cp == ' ')
|
||||
{
|
||||
cursor.x += space_size; // Move cursor for space
|
||||
continue;
|
||||
}
|
||||
else if (cp == '\n')
|
||||
{
|
||||
cursor.x = 0.0f;
|
||||
cursor.y += line_height;
|
||||
continue;
|
||||
}
|
||||
else if (cp == '^')
|
||||
{
|
||||
if (!(cp = DecodeUTF8Codepoint(p, end)))
|
||||
break;
|
||||
|
||||
if (cp == 'r') // reset color
|
||||
{
|
||||
curr_color = color;
|
||||
continue;
|
||||
}
|
||||
|
||||
curr_color = 0;
|
||||
|
||||
// parse color
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
curr_color >>= 8;
|
||||
uint32_t ch;
|
||||
if (cp >= '0' && cp <= '9')
|
||||
ch = cp - '0';
|
||||
else if (cp >= 'a' && cp <= 'f')
|
||||
ch = cp - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
curr_color |= (ch << 16);
|
||||
curr_color |= (ch << 20);
|
||||
|
||||
if (!(cp = DecodeUTF8Codepoint(p, end)))
|
||||
break;
|
||||
}
|
||||
|
||||
curr_color |= (color & 0xFF000000); // preserve alpha
|
||||
}
|
||||
|
||||
const FontGlyphData* glyph = font_->GetCodepointGlyph(cp);
|
||||
|
||||
if (!glyph)
|
||||
continue; // Dont even have "missing" glyph, font is shit
|
||||
|
||||
glm::vec2 p0 = cursor + glyph->offset;
|
||||
glm::vec2 p1 = p0 + glyph->size * scale;
|
||||
|
||||
PushRect(p0, glyph->uv0, p1, glyph->uv1, curr_color);
|
||||
cursor.x += glyph->advance * scale;
|
||||
}
|
||||
}
|
||||
|
||||
void gui::Context::Render()
|
||||
{
|
||||
va_.SetVBOData(vertices_.data(), vertices_.size() * sizeof(vertices_[0]));
|
||||
va_.SetIndices(indices_.data(), indices_.size());
|
||||
|
||||
static const gfx::HudPosition pos;
|
||||
|
||||
for (const auto& range : ranges_)
|
||||
{
|
||||
gfx::DrawHudCmd hudcmd;
|
||||
hudcmd.va = &va_;
|
||||
hudcmd.pos = &pos;
|
||||
hudcmd.texture = range.texture;
|
||||
hudcmd.first = range.start;
|
||||
hudcmd.count = range.count;
|
||||
dlist_.AddHUD(hudcmd);
|
||||
}
|
||||
}
|
||||
|
||||
void gui::Context::BeginTexture(const gfx::Texture* texture)
|
||||
{
|
||||
if (!ranges_.empty() && ranges_.back().texture == texture)
|
||||
return;
|
||||
|
||||
auto& range = ranges_.emplace_back();
|
||||
range.start = indices_.size();
|
||||
range.count = 0;
|
||||
range.texture = texture;
|
||||
}
|
||||
|
||||
void gui::Context::PushRect(const glm::vec2& p0, const glm::vec2& uv0, const glm::vec2& p1, const glm::vec2& uv1, uint32_t color)
|
||||
{
|
||||
uint32_t base_index = vertices_.size();
|
||||
|
||||
vertices_.emplace_back(glm::vec3(p0.x, p0.y, 0.0f), color, uv0);
|
||||
vertices_.emplace_back(glm::vec3(p1.x, p0.y, 0.0f), color, glm::vec2(uv1.x, uv0.y));
|
||||
vertices_.emplace_back(glm::vec3(p1.x, p1.y, 0.0f), color, uv1);
|
||||
vertices_.emplace_back(glm::vec3(p0.x, p1.y, 0.0f), color, glm::vec2(uv0.x, uv1.y));
|
||||
|
||||
indices_.push_back(base_index + 0);
|
||||
indices_.push_back(base_index + 1);
|
||||
indices_.push_back(base_index + 2);
|
||||
indices_.push_back(base_index + 0);
|
||||
indices_.push_back(base_index + 2);
|
||||
indices_.push_back(base_index + 3);
|
||||
|
||||
ranges_.back().count += 2; // 2 tris
|
||||
}
|
||||
63
src/gui/context.hpp
Normal file
63
src/gui/context.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "font.hpp"
|
||||
#include "gfx/vertex_array.hpp"
|
||||
#include "gfx/draw_list.hpp"
|
||||
|
||||
namespace gui
|
||||
{
|
||||
|
||||
struct GuiVertex
|
||||
{
|
||||
glm::vec3 pos;
|
||||
uint32_t color;
|
||||
glm::vec2 uv;
|
||||
};
|
||||
|
||||
struct GuiRange
|
||||
{
|
||||
size_t start;
|
||||
size_t count;
|
||||
const gfx::Texture* texture;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
glm::vec2 min;
|
||||
glm::vec2 max;
|
||||
};
|
||||
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(gfx::DrawList& dlist, std::shared_ptr<const Font> default_font);
|
||||
|
||||
void Begin();
|
||||
|
||||
glm::vec2 MeasureText(std::string_view text);
|
||||
void DrawText(std::string_view text, const glm::vec2& pos, uint32_t color = 0xFFFFFFFF, float scale = 1.0f);
|
||||
|
||||
void Render();
|
||||
|
||||
const std::shared_ptr<const Font>& GetFont() const { return font_; }
|
||||
|
||||
private:
|
||||
void BeginTexture(const gfx::Texture* texture);
|
||||
void PushRect(const glm::vec2& p0, const glm::vec2& uv0, const glm::vec2& p1, const glm::vec2& uv1, uint32_t color);
|
||||
|
||||
private:
|
||||
gfx::DrawList& dlist_;
|
||||
std::shared_ptr<const Font> font_;
|
||||
gfx::VertexArray va_;
|
||||
|
||||
// building
|
||||
std::vector<GuiVertex> vertices_;
|
||||
std::vector<uint32_t> indices_;
|
||||
std::vector<GuiRange> ranges_;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
#include "assets/cache.hpp"
|
||||
#include "assets/cmdfile.hpp"
|
||||
|
||||
std::shared_ptr<const gfx::Font> gfx::Font::LoadFromFile(const std::string& path)
|
||||
std::shared_ptr<const gui::Font> gui::Font::LoadFromFile(const std::string& path)
|
||||
{
|
||||
auto font = std::make_shared<Font>();
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "texture.hpp"
|
||||
#include "gfx/texture.hpp"
|
||||
|
||||
namespace gfx
|
||||
namespace gui
|
||||
{
|
||||
|
||||
using Codepoint = uint32_t;
|
||||
@ -87,12 +87,12 @@ public:
|
||||
return data ? data : glyphs_.Get(0); // try return missing codepoint glyph if missing
|
||||
}
|
||||
|
||||
const std::shared_ptr<const Texture>& GetTexture() const { return texture_; }
|
||||
const std::shared_ptr<const gfx::Texture>& GetTexture() const { return texture_; }
|
||||
|
||||
float GetLineHeight() const { return line_height_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<const Texture> texture_; // Texture atlas for the font
|
||||
std::shared_ptr<const gfx::Texture> texture_; // Texture atlas for the font
|
||||
CodepointMap<FontGlyphData> glyphs_;
|
||||
|
||||
float line_height_ = 0.0f; // Line height in pixels, used for text layout
|
||||
Loading…
x
Reference in New Issue
Block a user