mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[client] fonts: remove font rendering machinery
This commit is contained in:
parent
0c35d9b057
commit
f09738678e
@ -17,6 +17,9 @@ else()
|
|||||||
add_compile_options("-march=nehalem" "-mtune=generic")
|
add_compile_options("-march=nehalem" "-mtune=generic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(FONTCONFIG_PKGCONFIG REQUIRED fontconfig)
|
||||||
|
|
||||||
option(ENABLE_OPENGL "Enable the OpenGL renderer" ON)
|
option(ENABLE_OPENGL "Enable the OpenGL renderer" ON)
|
||||||
add_feature_info(ENABLE_OPENGL ENABLE_OPENGL "Legacy OpenGL renderer.")
|
add_feature_info(ENABLE_OPENGL ENABLE_OPENGL "Legacy OpenGL renderer.")
|
||||||
|
|
||||||
@ -97,6 +100,7 @@ include_directories(
|
|||||||
${PROJECT_SOURCE_DIR}/include
|
${PROJECT_SOURCE_DIR}/include
|
||||||
${CMAKE_BINARY_DIR}/include
|
${CMAKE_BINARY_DIR}/include
|
||||||
${GMP_INCLUDE_DIR}
|
${GMP_INCLUDE_DIR}
|
||||||
|
${FONTCONFIG_PKGCONFIG_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_libraries(
|
link_libraries(
|
||||||
@ -139,7 +143,6 @@ add_subdirectory("${PROJECT_TOP}/repos/cimgui" "${CMAKE_BINARY_DIR}/cimgui"
|
|||||||
|
|
||||||
add_subdirectory(displayservers)
|
add_subdirectory(displayservers)
|
||||||
add_subdirectory(renderers)
|
add_subdirectory(renderers)
|
||||||
add_subdirectory(fonts)
|
|
||||||
|
|
||||||
add_executable(looking-glass-client ${SOURCES})
|
add_executable(looking-glass-client ${SOURCES})
|
||||||
|
|
||||||
@ -147,12 +150,12 @@ target_compile_definitions(looking-glass-client PRIVATE CIMGUI_DEFINE_ENUMS_AND_
|
|||||||
|
|
||||||
target_link_libraries(looking-glass-client
|
target_link_libraries(looking-glass-client
|
||||||
${EXE_FLAGS}
|
${EXE_FLAGS}
|
||||||
|
${FONTCONFIG_PKGCONFIG_LIBRARIES}
|
||||||
lg_common
|
lg_common
|
||||||
displayservers
|
displayservers
|
||||||
lgmp
|
lgmp
|
||||||
purespice
|
purespice
|
||||||
renderers
|
renderers
|
||||||
fonts
|
|
||||||
cimgui
|
cimgui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
project(fonts LANGUAGES C)
|
|
||||||
|
|
||||||
set(FONT_H "${CMAKE_BINARY_DIR}/include/dynamic/fonts.h")
|
|
||||||
set(FONT_C "${CMAKE_BINARY_DIR}/src/fonts.c")
|
|
||||||
|
|
||||||
file(WRITE ${FONT_H} "#include \"interface/font.h\"\n\n")
|
|
||||||
file(APPEND ${FONT_H} "extern LG_Font * LG_Fonts[];\n\n")
|
|
||||||
|
|
||||||
file(WRITE ${FONT_C} "#include \"interface/font.h\"\n\n")
|
|
||||||
file(APPEND ${FONT_C} "#include <stddef.h>\n\n")
|
|
||||||
|
|
||||||
set(FONTS "_")
|
|
||||||
set(FONTS_LINK "_")
|
|
||||||
function(add_font name)
|
|
||||||
set(FONTS "${FONTS};${name}" PARENT_SCOPE)
|
|
||||||
set(FONTS_LINK "${FONTS_LINK};font_${name}" PARENT_SCOPE)
|
|
||||||
add_subdirectory(${name})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Add/remove fonts here!
|
|
||||||
add_font(freetype)
|
|
||||||
|
|
||||||
list(REMOVE_AT FONTS 0)
|
|
||||||
list(REMOVE_AT FONTS_LINK 0)
|
|
||||||
|
|
||||||
list(LENGTH FONTS FONT_COUNT)
|
|
||||||
file(APPEND ${FONT_H} "#define LG_FONT_COUNT ${FONT_COUNT}\n")
|
|
||||||
|
|
||||||
foreach(font ${FONTS})
|
|
||||||
file(APPEND ${FONT_C} "extern LG_Font LGF_${font};\n")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
file(APPEND ${FONT_C} "\nconst LG_Font * LG_Fonts[] =\n{\n")
|
|
||||||
foreach(font ${FONTS})
|
|
||||||
file(APPEND ${FONT_C} " &LGF_${font},\n")
|
|
||||||
endforeach()
|
|
||||||
file(APPEND ${FONT_C} " NULL\n};\n\n")
|
|
||||||
|
|
||||||
add_library(fonts STATIC ${FONT_C})
|
|
||||||
target_link_libraries(fonts ${FONTS_LINK})
|
|
@ -1,26 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
project(font_freetype LANGUAGES C)
|
|
||||||
|
|
||||||
find_package(PkgConfig)
|
|
||||||
pkg_check_modules(FONT_FREETYPE_PKGCONFIG REQUIRED
|
|
||||||
freetype2
|
|
||||||
fontconfig
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(font_freetype STATIC
|
|
||||||
src/freetype.c
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(font_freetype
|
|
||||||
${FONT_FREETYPE_PKGCONFIG_LIBRARIES}
|
|
||||||
lg_common
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(font_freetype
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
PRIVATE
|
|
||||||
src
|
|
||||||
${FONT_FREETYPE_PKGCONFIG_INCLUDE_DIRS}
|
|
||||||
)
|
|
@ -1,325 +0,0 @@
|
|||||||
/**
|
|
||||||
* Looking Glass
|
|
||||||
* Copyright (C) 2017-2021 The Looking Glass Authors
|
|
||||||
* https://looking-glass.io
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
||||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "interface/font.h"
|
|
||||||
#include "common/debug.h"
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include <fontconfig/fontconfig.h>
|
|
||||||
|
|
||||||
static int g_initCount = 0;
|
|
||||||
static FcConfig * g_fontConfig = NULL;
|
|
||||||
static FT_Library g_ft;
|
|
||||||
|
|
||||||
struct Inst
|
|
||||||
{
|
|
||||||
FT_Face face;
|
|
||||||
unsigned int height;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool lgf_freetype_create(LG_FontObj * opaque, const char * font_name, unsigned int size)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (g_initCount == 0)
|
|
||||||
{
|
|
||||||
if (FT_Init_FreeType(&g_ft))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FT_Init_FreeType Failed");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_fontConfig = FcInitLoadConfigAndFonts();
|
|
||||||
if (!g_fontConfig)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FcInitLoadConfigAndFonts Failed");
|
|
||||||
goto fail_init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*opaque = malloc(sizeof(struct Inst));
|
|
||||||
if (!*opaque)
|
|
||||||
{
|
|
||||||
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct Inst));
|
|
||||||
goto fail_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(*opaque, 0, sizeof(struct Inst));
|
|
||||||
struct Inst * this = (struct Inst *)*opaque;
|
|
||||||
|
|
||||||
if (!font_name)
|
|
||||||
font_name = "FreeMono";
|
|
||||||
|
|
||||||
FcPattern * pat = FcNameParse((const FcChar8*)font_name);
|
|
||||||
if (!pat)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FCNameParse failed");
|
|
||||||
goto fail_opaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
FcConfigSubstitute(g_fontConfig, pat, FcMatchPattern);
|
|
||||||
FcDefaultSubstitute(pat);
|
|
||||||
FcResult result;
|
|
||||||
FcChar8 * file = NULL;
|
|
||||||
FcPattern * match = FcFontMatch(g_fontConfig, pat, &result);
|
|
||||||
|
|
||||||
if (!match)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FcFontMatch Failed");
|
|
||||||
goto fail_parse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultMatch)
|
|
||||||
{
|
|
||||||
if (FT_New_Face(g_ft, (char *) file, 0, &this->face))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FT_New_Face Failed");
|
|
||||||
goto fail_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FT_Select_Charmap(this->face, ft_encoding_unicode))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("FT_Select_Charmap failed");
|
|
||||||
FT_Done_Face(this->face);
|
|
||||||
goto fail_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(this->face, 0, size);
|
|
||||||
this->height = size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to locate the requested font: %s", font_name);
|
|
||||||
goto fail_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
++g_initCount;
|
|
||||||
ret = true;
|
|
||||||
|
|
||||||
fail_match:
|
|
||||||
FcPatternDestroy(match);
|
|
||||||
|
|
||||||
fail_parse:
|
|
||||||
FcPatternDestroy(pat);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
fail_opaque:
|
|
||||||
free(this);
|
|
||||||
*opaque = NULL;
|
|
||||||
|
|
||||||
fail_config:
|
|
||||||
if (g_initCount == 0)
|
|
||||||
{
|
|
||||||
FcConfigDestroy(g_fontConfig);
|
|
||||||
g_fontConfig = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail_init:
|
|
||||||
if (g_initCount == 0)
|
|
||||||
FT_Done_FreeType(g_ft);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lgf_freetype_destroy(LG_FontObj opaque)
|
|
||||||
{
|
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
|
||||||
|
|
||||||
if (this->face)
|
|
||||||
FT_Done_Face(this->face);
|
|
||||||
free(this);
|
|
||||||
|
|
||||||
if (--g_initCount == 0)
|
|
||||||
{
|
|
||||||
FcConfigDestroy(g_fontConfig);
|
|
||||||
g_fontConfig = NULL;
|
|
||||||
|
|
||||||
FT_Done_FreeType(g_ft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A very simple UTF-8 decoder that assumes the input is valid.
|
|
||||||
static unsigned int utf8_decode(const char * str)
|
|
||||||
{
|
|
||||||
const unsigned char * ptr = (const unsigned char *) str;
|
|
||||||
// Handle the 4 byte case: 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx.
|
|
||||||
if ((*ptr & 0xf8) == 0xf0)
|
|
||||||
return (ptr[0] & 0x07) << 18 | (ptr[1] & 0x3f) << 12 | (ptr[2] & 0x3f) << 6 | (ptr[3] & 0x3f);
|
|
||||||
// Handle the 3 byte case: 1110 xxxx 10xx xxxx 10xx xxxx.
|
|
||||||
else if ((*ptr & 0xf0) == 0xe0)
|
|
||||||
return (ptr[0] & 0x0f) << 12 | (ptr[1] & 0x3f) << 6 | (ptr[2] & 0x3f);
|
|
||||||
// Handle the 2 byte case: 110x xxxx 10xx xxxx.
|
|
||||||
else if ((*ptr & 0xe0) == 0xc0)
|
|
||||||
return (ptr[0] & 0x1f) << 6 | (ptr[1] & 0x3f);
|
|
||||||
// Everything else is the 1 byte case.
|
|
||||||
else
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the length of the current UTF-8 character. Assumes the input is valid.
|
|
||||||
static unsigned int utf8_advance(const char * str)
|
|
||||||
{
|
|
||||||
const unsigned char * ptr = (const unsigned char *) str;
|
|
||||||
// 4 byte case starts with 1111 0xxx.
|
|
||||||
if ((*ptr & 0xf8) == 0xf0)
|
|
||||||
return 4;
|
|
||||||
// 3 byte case starts with 1110 xxxx.
|
|
||||||
else if ((*ptr & 0xf0) == 0xe0)
|
|
||||||
return 3;
|
|
||||||
// 2 byte case starts with 110x xxxx.
|
|
||||||
else if ((*ptr & 0xe0) == 0xc0)
|
|
||||||
return 2;
|
|
||||||
// Everything else is the 1 byte case.
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LG_FontBitmap * lgf_freetype_render(LG_FontObj opaque, unsigned int fg_color, const char * text)
|
|
||||||
{
|
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
|
||||||
|
|
||||||
int width = 0;
|
|
||||||
int row = 0;
|
|
||||||
int rowWidth = 0;
|
|
||||||
int topAscend = 0;
|
|
||||||
int bottomDescend = 0;
|
|
||||||
|
|
||||||
for (const char * ptr = text; *ptr; ptr += utf8_advance(ptr))
|
|
||||||
{
|
|
||||||
unsigned int ch = utf8_decode(ptr);
|
|
||||||
if (ch == '\n')
|
|
||||||
{
|
|
||||||
if (!ptr[1])
|
|
||||||
break;
|
|
||||||
if (rowWidth > width)
|
|
||||||
width = rowWidth;
|
|
||||||
rowWidth = bottomDescend = 0;
|
|
||||||
++row;
|
|
||||||
}
|
|
||||||
else if (FT_Load_Char(this->face, ch, FT_LOAD_RENDER))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to load character: %c", *ptr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FT_GlyphSlot glyph = this->face->glyph;
|
|
||||||
rowWidth += glyph->advance.x / 64;
|
|
||||||
|
|
||||||
int descend = glyph->bitmap.rows - glyph->bitmap_top;
|
|
||||||
if (descend > bottomDescend)
|
|
||||||
bottomDescend = descend;
|
|
||||||
if (row == 0 && glyph->bitmap_top > topAscend)
|
|
||||||
topAscend = glyph->bitmap_top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rowWidth > width)
|
|
||||||
width = rowWidth;
|
|
||||||
|
|
||||||
int height = topAscend + this->height * row + bottomDescend;
|
|
||||||
uint32_t * pixels = calloc(width * height, sizeof(uint32_t));
|
|
||||||
|
|
||||||
if (!pixels)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to allocate memory for font pixels");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int baseline = topAscend;
|
|
||||||
int x = 0;
|
|
||||||
|
|
||||||
unsigned int r = (fg_color & 0xff000000) >> 24;
|
|
||||||
unsigned int g = (fg_color & 0x00ff0000) >> 16;
|
|
||||||
unsigned int b = (fg_color & 0x0000ff00) >> 8;
|
|
||||||
uint32_t color = (r << 0) | (g << 8) | (b << 16);
|
|
||||||
|
|
||||||
for (const char * ptr = text; *ptr; ptr += utf8_advance(ptr))
|
|
||||||
{
|
|
||||||
unsigned int ch = utf8_decode(ptr);
|
|
||||||
if (ch == '\n')
|
|
||||||
{
|
|
||||||
baseline += this->height;
|
|
||||||
x = 0;
|
|
||||||
}
|
|
||||||
else if (FT_Load_Char(this->face, ch, FT_LOAD_RENDER))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to load character: U+%x", ch);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FT_GlyphSlot glyph = this->face->glyph;
|
|
||||||
int start = baseline - glyph->bitmap_top;
|
|
||||||
int pitch = width;
|
|
||||||
|
|
||||||
if (glyph->bitmap.pitch < 0)
|
|
||||||
{
|
|
||||||
start += glyph->bitmap.rows - 1;
|
|
||||||
pitch = -pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < glyph->bitmap.rows; ++i)
|
|
||||||
for (int j = 0; j < glyph->bitmap.width; ++j)
|
|
||||||
pixels[(start + i) * pitch + x + j + glyph->bitmap_left] = color |
|
|
||||||
(uint32_t)glyph->bitmap.buffer[i * glyph->bitmap.pitch + j] << 24;
|
|
||||||
|
|
||||||
x += glyph->advance.x / 64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LG_FontBitmap * out = malloc(sizeof(LG_FontBitmap));
|
|
||||||
if (!out)
|
|
||||||
{
|
|
||||||
free(pixels);
|
|
||||||
DEBUG_ERROR("Failed to allocate memory for font bitmap");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
out->width = width;
|
|
||||||
out->height = height;
|
|
||||||
out->bpp = 4;
|
|
||||||
out->pixels = (uint8_t *) pixels;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lgf_freetype_release(LG_FontObj opaque, LG_FontBitmap * font)
|
|
||||||
{
|
|
||||||
LG_FontBitmap * bitmap = (LG_FontBitmap *)font;
|
|
||||||
free(bitmap->pixels);
|
|
||||||
free(bitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LG_Font LGF_freetype =
|
|
||||||
{
|
|
||||||
.name = "freetype",
|
|
||||||
.create = lgf_freetype_create,
|
|
||||||
.destroy = lgf_freetype_destroy,
|
|
||||||
.render = lgf_freetype_render,
|
|
||||||
.release = lgf_freetype_release
|
|
||||||
};
|
|
@ -54,7 +54,6 @@ target_link_libraries(renderer_EGL
|
|||||||
${RENDERER_EGL_PKGCONFIG_LIBRARIES}
|
${RENDERER_EGL_PKGCONFIG_LIBRARIES}
|
||||||
${RENDERER_EGL_OPT_PKGCONFIG_LIBRARIES}
|
${RENDERER_EGL_OPT_PKGCONFIG_LIBRARIES}
|
||||||
lg_common
|
lg_common
|
||||||
fonts
|
|
||||||
|
|
||||||
cimgui
|
cimgui
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,6 @@ target_compile_definitions(renderer_OpenGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUC
|
|||||||
target_link_libraries(renderer_OpenGL
|
target_link_libraries(renderer_OpenGL
|
||||||
${RENDERER_OPENGL_PKGCONFIG_LIBRARIES}
|
${RENDERER_OPENGL_PKGCONFIG_LIBRARIES}
|
||||||
lg_common
|
lg_common
|
||||||
fonts
|
|
||||||
|
|
||||||
cimgui
|
cimgui
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user