Add skeleton of TextRenderer
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
@@ -14,6 +14,7 @@ pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_check_modules(LIBPORTAL REQUIRED IMPORTED_TARGET libportal)
|
||||
pkg_check_modules(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon)
|
||||
pkg_check_modules(FONTCONFIG REQUIRED IMPORTED_TARGET fontconfig)
|
||||
pkg_check_modules(HARFBUZZ REQUIRED IMPORTED_TARGET harfbuzz)
|
||||
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
|
||||
pkg_check_modules(WLR_PROTOCOLS REQUIRED wlr-protocols)
|
||||
|
||||
@@ -30,6 +31,18 @@ set(PLATFORM DRM)
|
||||
set(BUILD_EXAMPLES OFF)
|
||||
FetchContent_MakeAvailable(raylib)
|
||||
|
||||
FetchContent_Declare(
|
||||
msdfgen
|
||||
GIT_REPOSITORY https://github.com/Chlumsky/msdfgen.git
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
set(MSDFGEN_BUILD_STANDALONE OFF)
|
||||
set(MSDFGEN_USE_VCPKG OFF)
|
||||
set(MSDFGEN_USE_SKIA OFF)
|
||||
set(MSDFGEN_DISABLE_SVG ON)
|
||||
set(MSDFGEN_DISABLE_PNG ON)
|
||||
FetchContent_MakeAvailable(msdfgen)
|
||||
|
||||
find_program(WAYLAND_SCANNER wayland-scanner REQUIRED)
|
||||
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
@@ -118,6 +131,7 @@ add_executable(waylight
|
||||
${GEN_C_PRIVATES}
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/App.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/TextRenderer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Tick.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
|
||||
)
|
||||
@@ -136,8 +150,10 @@ target_link_libraries(waylight PRIVATE
|
||||
PkgConfig::LIBPORTAL
|
||||
PkgConfig::XKBCOMMON
|
||||
PkgConfig::FONTCONFIG
|
||||
PkgConfig::HARFBUZZ
|
||||
|
||||
raylib
|
||||
msdfgen::msdfgen-core
|
||||
|
||||
m
|
||||
dl
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
glib
|
||||
libxkbcommon
|
||||
fontconfig
|
||||
harfbuzz
|
||||
]
|
||||
++ buildInputs
|
||||
++ nativeBuildInputs
|
||||
|
||||
43
src/App.cpp
43
src/App.cpp
@@ -1,11 +1,11 @@
|
||||
#include "App.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <poll.h>
|
||||
#include <print>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -27,35 +27,6 @@
|
||||
#include "blur-client-protocol.h"
|
||||
#include "ext-background-effect-v1-client-protocol.h"
|
||||
|
||||
auto find_font_path(std::string_view path = "sans-serif:style=Regular")
|
||||
-> std::optional<std::string>
|
||||
{
|
||||
if (!FcInit())
|
||||
return std::nullopt;
|
||||
|
||||
std::string query(path);
|
||||
FcPattern *pattern
|
||||
= FcNameParse(reinterpret_cast<FcChar8 const *>(query.c_str()));
|
||||
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
FcResult result;
|
||||
FcPattern *font = FcFontMatch(nullptr, pattern, &result);
|
||||
|
||||
std::optional<std::string> final_path;
|
||||
|
||||
if (font) {
|
||||
FcChar8 *file;
|
||||
if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
|
||||
final_path = reinterpret_cast<char *>(file);
|
||||
FcPatternDestroy(font);
|
||||
}
|
||||
|
||||
FcPatternDestroy(pattern);
|
||||
FcFini();
|
||||
return final_path;
|
||||
}
|
||||
|
||||
auto TypingBuffer::push_utf8(char const *s) -> void
|
||||
{
|
||||
for (unsigned char const *p = reinterpret_cast<unsigned char const *>(s);
|
||||
@@ -83,11 +54,6 @@ auto TypingBuffer::push_utf8(char const *s) -> void
|
||||
|
||||
App::App()
|
||||
{
|
||||
{
|
||||
auto const path = find_font_path();
|
||||
if (path)
|
||||
std::println("font path = {}", *path);
|
||||
}
|
||||
init_wayland();
|
||||
init_egl();
|
||||
init_signal();
|
||||
@@ -330,6 +296,13 @@ auto App::init_egl() -> void
|
||||
ensure_egl_surface();
|
||||
|
||||
InitWindow(m_win_w, m_win_h, "");
|
||||
|
||||
m_tr = TextRenderer();
|
||||
auto const font = find_font_path();
|
||||
assert(font && "Could not find font");
|
||||
auto const font_handle = m_tr->load_font(*font);
|
||||
assert(font_handle && "Could not load font");
|
||||
m_font = *font_handle;
|
||||
}
|
||||
|
||||
auto App::init_signal() -> void
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory_resource>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
@@ -18,6 +17,7 @@ extern "C" {
|
||||
#include <wayland-egl.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "TextRenderer.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
@@ -139,6 +139,9 @@ private:
|
||||
}
|
||||
} m_kbd;
|
||||
|
||||
std::optional<TextRenderer> m_tr { std::nullopt };
|
||||
FontHandle m_font;
|
||||
|
||||
enum_array<Theme, ColorScheme> m_themes { make_default_themes() };
|
||||
Theme m_active_theme { Theme::Light };
|
||||
|
||||
|
||||
104
src/TextRenderer.cpp
Normal file
104
src/TextRenderer.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "TextRenderer.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
TextRenderer::TextRenderer()
|
||||
{
|
||||
static char const msdf_fs_data[] {
|
||||
#embed "msdf.fs"
|
||||
, 0
|
||||
};
|
||||
m_msdf_shader = LoadShaderFromMemory(nullptr, msdf_fs_data);
|
||||
assert(IsShaderValid(m_msdf_shader));
|
||||
}
|
||||
|
||||
TextRenderer::~TextRenderer() { UnloadShader(m_msdf_shader); }
|
||||
|
||||
auto TextRenderer::measure_text(FontHandle const font,
|
||||
std::string_view const text, int const size) -> Vector2
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return {};
|
||||
}
|
||||
|
||||
auto TextRenderer::draw_text(FontHandle const font, std::string_view const text,
|
||||
Vector2 const pos, int const size, Color const color) -> void
|
||||
{
|
||||
int const pos_x = pos.x;
|
||||
int const pos_y = pos.y;
|
||||
// Don't use pos from here on out!
|
||||
// FIXME: Implement.
|
||||
(void)pos_x, (void)pos_y;
|
||||
}
|
||||
|
||||
auto TextRenderer::load_font(std::filesystem::path const &path)
|
||||
-> std::optional<FontHandle>
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto TextRenderer::unload_font(FontHandle const font)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
}
|
||||
|
||||
auto find_font_path(std::string_view path)
|
||||
-> std::optional<std::filesystem::path>
|
||||
{
|
||||
static std::once_flag fc_once;
|
||||
std::call_once(fc_once, []() {
|
||||
if (FcInit())
|
||||
std::atexit([] { FcFini(); });
|
||||
});
|
||||
|
||||
static std::mutex m;
|
||||
static std::unordered_map<std::string, std::optional<std::string>> cache;
|
||||
|
||||
std::string const key(path);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m);
|
||||
if (auto it = cache.find(key); it != cache.end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
FcPattern *pattern
|
||||
= FcNameParse(reinterpret_cast<FcChar8 const *>(key.c_str()));
|
||||
if (!pattern) {
|
||||
std::scoped_lock lock(m);
|
||||
return cache[key] = std::nullopt;
|
||||
}
|
||||
|
||||
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
FcResult result;
|
||||
FcPattern *font = FcFontMatch(nullptr, pattern, &result);
|
||||
|
||||
std::optional<std::string> final_path;
|
||||
if (font) {
|
||||
FcChar8 *file;
|
||||
if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
|
||||
final_path = reinterpret_cast<char *>(file);
|
||||
FcPatternDestroy(font);
|
||||
}
|
||||
|
||||
FcPatternDestroy(pattern);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m);
|
||||
cache[key] = final_path;
|
||||
}
|
||||
return final_path;
|
||||
}
|
||||
56
src/TextRenderer.hpp
Normal file
56
src/TextRenderer.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
struct FontHandle {
|
||||
auto operator()() const -> auto const & { return id; }
|
||||
|
||||
private:
|
||||
usize id;
|
||||
};
|
||||
|
||||
struct TextRenderer {
|
||||
TextRenderer(); // Requires raylib to be initialized!
|
||||
~TextRenderer();
|
||||
|
||||
auto measure_text(FontHandle const font, std::string_view const text,
|
||||
int const size = 16) -> Vector2;
|
||||
auto draw_text(FontHandle const font, std::string_view const text,
|
||||
Vector2 const pos, int const size = 16, Color const color = WHITE)
|
||||
-> void;
|
||||
|
||||
auto load_font(std::filesystem::path const &path)
|
||||
-> std::optional<FontHandle>;
|
||||
auto unload_font(FontHandle const font);
|
||||
|
||||
private:
|
||||
struct FontData {
|
||||
struct Glyph {
|
||||
struct Rect {
|
||||
float top, left, right, bottom;
|
||||
};
|
||||
|
||||
float advance;
|
||||
Rect plane_bounds;
|
||||
Rect glyph_bounds;
|
||||
};
|
||||
|
||||
Texture2D atlas;
|
||||
Image atlas_img;
|
||||
std::filesystem::path font_path;
|
||||
std::unordered_map<u32, Glyph> glyphs;
|
||||
};
|
||||
|
||||
Shader m_msdf_shader;
|
||||
|
||||
std::vector<FontData> m_font_data;
|
||||
};
|
||||
|
||||
auto find_font_path(std::string_view path = "sans-serif:style=Regular")
|
||||
-> std::optional<std::filesystem::path>;
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
@@ -11,7 +13,7 @@ using i64 = std::int64_t;
|
||||
using usize = std::uintptr_t;
|
||||
using isize = std::intptr_t;
|
||||
|
||||
inline auto rune_to_string(uint32_t cp) -> char const *
|
||||
[[maybe_unused]] static inline auto rune_to_string(uint32_t cp) -> char const *
|
||||
{
|
||||
static char utf8[5] = { 0 };
|
||||
for (auto &c : utf8)
|
||||
|
||||
34
src/msdf.fs
Normal file
34
src/msdf.fs
Normal file
@@ -0,0 +1,34 @@
|
||||
#version 100
|
||||
#extension GL_OES_standard_derivatives : enable
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
uniform float pxRange;
|
||||
|
||||
float median(float r, float g, float b) {
|
||||
return max(min(r, g), min(max(r, g), b));
|
||||
}
|
||||
|
||||
float screenPxRange(vec2 uv) {
|
||||
vec2 duv_dx = dFdx(uv);
|
||||
vec2 duv_dy = dFdy(uv);
|
||||
float scale = 0.5 * (length(duv_dx) + length(duv_dy));
|
||||
return max(scale * pxRange, 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 msd = texture2D(texture0, fragTexCoord).rgb;
|
||||
float sd = median(msd.r, msd.g, msd.b);
|
||||
float spx = screenPxRange(fragTexCoord);
|
||||
float dist = spx * (sd - 0.5);
|
||||
float opacity = clamp(dist + 0.5, 0.0, 1.0);
|
||||
|
||||
gl_FragColor = vec4(fragColor.rgb, fragColor.a * opacity) * colDiffuse;
|
||||
}
|
||||
Reference in New Issue
Block a user