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(LIBPORTAL REQUIRED IMPORTED_TARGET libportal)
|
||||||
pkg_check_modules(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon)
|
pkg_check_modules(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon)
|
||||||
pkg_check_modules(FONTCONFIG REQUIRED IMPORTED_TARGET fontconfig)
|
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(WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
|
||||||
pkg_check_modules(WLR_PROTOCOLS REQUIRED wlr-protocols)
|
pkg_check_modules(WLR_PROTOCOLS REQUIRED wlr-protocols)
|
||||||
|
|
||||||
@@ -30,6 +31,18 @@ set(PLATFORM DRM)
|
|||||||
set(BUILD_EXAMPLES OFF)
|
set(BUILD_EXAMPLES OFF)
|
||||||
FetchContent_MakeAvailable(raylib)
|
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)
|
find_program(WAYLAND_SCANNER wayland-scanner REQUIRED)
|
||||||
|
|
||||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||||
@@ -118,6 +131,7 @@ add_executable(waylight
|
|||||||
${GEN_C_PRIVATES}
|
${GEN_C_PRIVATES}
|
||||||
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/App.cpp
|
${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/Tick.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
|
||||||
)
|
)
|
||||||
@@ -136,8 +150,10 @@ target_link_libraries(waylight PRIVATE
|
|||||||
PkgConfig::LIBPORTAL
|
PkgConfig::LIBPORTAL
|
||||||
PkgConfig::XKBCOMMON
|
PkgConfig::XKBCOMMON
|
||||||
PkgConfig::FONTCONFIG
|
PkgConfig::FONTCONFIG
|
||||||
|
PkgConfig::HARFBUZZ
|
||||||
|
|
||||||
raylib
|
raylib
|
||||||
|
msdfgen::msdfgen-core
|
||||||
|
|
||||||
m
|
m
|
||||||
dl
|
dl
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
glib
|
glib
|
||||||
libxkbcommon
|
libxkbcommon
|
||||||
fontconfig
|
fontconfig
|
||||||
|
harfbuzz
|
||||||
]
|
]
|
||||||
++ buildInputs
|
++ buildInputs
|
||||||
++ nativeBuildInputs
|
++ nativeBuildInputs
|
||||||
|
|||||||
43
src/App.cpp
43
src/App.cpp
@@ -1,11 +1,11 @@
|
|||||||
#include "App.hpp"
|
#include "App.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <print>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -27,35 +27,6 @@
|
|||||||
#include "blur-client-protocol.h"
|
#include "blur-client-protocol.h"
|
||||||
#include "ext-background-effect-v1-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
|
auto TypingBuffer::push_utf8(char const *s) -> void
|
||||||
{
|
{
|
||||||
for (unsigned char const *p = reinterpret_cast<unsigned char const *>(s);
|
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()
|
App::App()
|
||||||
{
|
{
|
||||||
{
|
|
||||||
auto const path = find_font_path();
|
|
||||||
if (path)
|
|
||||||
std::println("font path = {}", *path);
|
|
||||||
}
|
|
||||||
init_wayland();
|
init_wayland();
|
||||||
init_egl();
|
init_egl();
|
||||||
init_signal();
|
init_signal();
|
||||||
@@ -330,6 +296,13 @@ auto App::init_egl() -> void
|
|||||||
ensure_egl_surface();
|
ensure_egl_surface();
|
||||||
|
|
||||||
InitWindow(m_win_w, m_win_h, "");
|
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
|
auto App::init_signal() -> void
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory_resource>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -18,6 +17,7 @@ extern "C" {
|
|||||||
#include <wayland-egl.h>
|
#include <wayland-egl.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
#include "TextRenderer.hpp"
|
||||||
#include "Theme.hpp"
|
#include "Theme.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
@@ -139,6 +139,9 @@ private:
|
|||||||
}
|
}
|
||||||
} m_kbd;
|
} m_kbd;
|
||||||
|
|
||||||
|
std::optional<TextRenderer> m_tr { std::nullopt };
|
||||||
|
FontHandle m_font;
|
||||||
|
|
||||||
enum_array<Theme, ColorScheme> m_themes { make_default_themes() };
|
enum_array<Theme, ColorScheme> m_themes { make_default_themes() };
|
||||||
Theme m_active_theme { Theme::Light };
|
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>
|
#include <cstdint>
|
||||||
|
|
||||||
using u8 = std::uint8_t;
|
using u8 = std::uint8_t;
|
||||||
@@ -11,7 +13,7 @@ using i64 = std::int64_t;
|
|||||||
using usize = std::uintptr_t;
|
using usize = std::uintptr_t;
|
||||||
using isize = std::intptr_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 };
|
static char utf8[5] = { 0 };
|
||||||
for (auto &c : utf8)
|
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