[renderer] Star work on adding FreeType support

Right now, this just initializes the library and loads a font into
memory, preloading a given set of characters (specified by unicode
values).
This commit is contained in:
Bill Currie 2022-08-27 17:53:03 +09:00
parent d39f02ecfc
commit 4d5b38f0c9
8 changed files with 291 additions and 2 deletions

View file

@ -26,7 +26,7 @@ NOCONV_DIST= \
BUILT_SOURCES = $(top_srcdir)/.version
#AM_CFLAGS= @PREFER_NON_PIC@
AM_CPPFLAGS= -I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(FNM_FLAGS) $(NCURSES_CFLAGS)
AM_CPPFLAGS= -I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(FNM_FLAGS) $(NCURSES_CFLAGS) $(FREETYPE_CFLAGS)
common_ldflags= -export-dynamic @PTHREAD_LDFLAGS@

15
config.d/freetype.m4 Normal file
View file

@ -0,0 +1,15 @@
AC_ARG_ENABLE(freetype,
AS_HELP_STRING([--disable-freetype], [disable freetype support]))
if test "x$enable_freetype" != "xno"; then
if test "x$PKG_CONFIG" != "x"; then
PKG_CHECK_MODULES([FREETYPE], [freetype2], HAVE_FREETYPE=yes, HAVE_FREETYPE=no)
fi
else
HAVE_FREETYPE=no
FREETYPE_LIBS=
fi
AC_SUBST(FREETYPE_LIBS)
if test "x$HAVE_FREETYPE" == "xyes"; then
AC_DEFINE(HAVE_FREETYPE, 1, [Define if you have the freetype library])
fi

View file

@ -68,6 +68,7 @@ m4_include(config.d/x11.m4)
m4_include(config.d/sdl.m4)
m4_include(config.d/curses.m4)
m4_include(config.d/freetype.m4)
dnl ==================================================================
dnl Checks for system type

66
include/r_font.h Normal file
View file

@ -0,0 +1,66 @@
/*
r_font.h
Renderer font management
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2022/8/26
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:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef __r_font_h
#define __r_font_h
#include <ft2build.h>
#include FT_FREETYPE_H
#include "QF/hash.h"
#include "QF/progs.h" //FIXME for PR_RESMAP
#include "QF/ui/vrect.h"
#include "QF/simd/types.h"
#include "r_scrap.h"
typedef struct rglyph_s {
struct rfont_s *font;
vrect_t *rect;
vec2i_t bearing;
int advance;
int charcode;
} rglyph_t;
typedef struct rfont_s {
void *font_resource;
FT_Face face;
rscrap_t scrap;
byte *scrap_bitmap;
hashtab_t *glyphmap;
PR_RESMAP(rglyph_t) glyphs;
} rfont_t;
void R_FontInit (void);
void R_FontFree (rfont_t *font);
rfont_t *R_FontLoad (QFile *font_file, int size, const int *preload);
#endif//__r_font_h

View file

@ -30,13 +30,15 @@ video_renderer_common_sources = \
libs/video/renderer/r_billboard.c \
libs/video/renderer/r_dyn_textures.c \
libs/video/renderer/r_ent.c \
libs/video/renderer/r_font.c \
libs/video/renderer/r_iqm.c \
libs/video/renderer/r_sprite.c \
libs/video/renderer/vid_common.c
renderer_libs= \
@vid_render_static_plugin_libs@ \
libs/util/libQFutil.la
libs/util/libQFutil.la \
$(FREETYPE_LIBS)
libs_video_renderer_libQFrenderer_la_LDFLAGS= @STATIC@
libs_video_renderer_libQFrenderer_la_LIBADD= $(renderer_libs)

View file

@ -0,0 +1,186 @@
/*
r_font.c
Renderer font management management
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2022/8/26
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:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <math.h>
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/math/bitop.h"
#include "r_font.h"
#include "compat.h"
static FT_Library ft;
static uintptr_t
glyph_get_hash (const void *_glyph, void *unused)
{
__auto_type glyph = (const rglyph_t *) _glyph;
return glyph->charcode;
}
static int
glyph_compare (const void *_a, const void *_b, void *unused)
{
__auto_type a = (const rglyph_t *) _a;
__auto_type b = (const rglyph_t *) _b;
return a->charcode == b->charcode;
}
static rglyph_t *
alloc_glyph (rfont_t *font)
{
return PR_RESNEW(font->glyphs);
}
static void
free_glyph (rfont_t *font, rglyph_t *glyph)
{
PR_RESFREE (font->glyphs, glyph);
}
static void
copy_glypn (rglyph_t *glyph, FT_GlyphSlot src_glyph)
{
int dst_pitch = glyph->font->scrap.width;
byte *dst = glyph->font->scrap_bitmap + glyph->rect->x + glyph->rect->y * dst_pitch;
int src_pitch = src_glyph->bitmap.pitch;
byte *src = src_glyph->bitmap.buffer;
for (unsigned i = 0; i < src_glyph->bitmap.rows; i++) {
memcpy (dst, src, src_glyph->bitmap.width);
dst += dst_pitch;
src += src_pitch;
}
}
static void
glyphmap_free_glyph (void *_g, void *_f)
{
rglyph_t *glyph = _g;
rfont_t *font = _f;
free_glyph (font, glyph);
}
VISIBLE void
R_FontInit (void)
{
if (FT_Init_FreeType (&ft)) {
Sys_Error ("Could not init FreeType library");
}
}
VISIBLE void
R_FontFree (rfont_t *font)
{
if (font->face) {
FT_Done_Face (font->face);
}
if (font->glyphmap) {
Hash_DelTable (font->glyphmap);
}
if (font->scrap.rects || font->scrap.free_rects) {
R_ScrapDelete (&font->scrap);
}
free (font->scrap_bitmap);
free (font->font_resource);
free (font);
}
VISIBLE rfont_t *
R_FontLoad (QFile *font_file, int size, const int *preload)
{
byte *font_data = QFS_LoadFile (font_file, 0);
if (!font_data) {
return 0;
}
size_t font_size = Qfilesize (font_file);;
rfont_t *font = calloc (1, sizeof (rfont_t));
font->font_resource = font_data;
if (FT_New_Memory_Face (ft, font_data, font_size, 0, &font->face)) {
R_FontFree (font);
return 0;
}
font->glyphmap = Hash_NewTable (0x10000, 0, glyphmap_free_glyph, font, 0);
Hash_SetHashCompare (font->glyphmap, glyph_get_hash, glyph_compare);
FT_Set_Pixel_Sizes(font->face, 0, size);
int pixels = 0;
for (const int *c = preload; *c; c++) {
rglyph_t search = { .charcode = *c };
rglyph_t *glyph = Hash_FindElement (font->glyphmap, &search);
if (glyph) {
continue;
}
if (FT_Load_Char(font->face, *c, FT_LOAD_DEFAULT)) {
continue;
}
__auto_type g = font->face->glyph;
pixels += g->bitmap.width * g->bitmap.rows;
glyph = alloc_glyph (font);
glyph->charcode = *c;
Hash_AddElement (font->glyphmap, glyph);
}
Hash_FlushTable (font->glyphmap);
pixels = sqrt (2 * pixels);
pixels = BITOP_RUP (pixels);
R_ScrapInit (&font->scrap, pixels, pixels);
font->scrap_bitmap = calloc (1, pixels * pixels);
for (const int *c = preload; *c; c++) {
rglyph_t search = { .charcode = *c };
rglyph_t *glyph = Hash_FindElement (font->glyphmap, &search);
if (glyph) {
continue;
}
if (FT_Load_Char(font->face, *c, FT_LOAD_RENDER)) {
continue;
}
__auto_type g = font->face->glyph;
int width = g->bitmap.width;
int height = g->bitmap.rows;
glyph = alloc_glyph (font);
glyph->font = font;
glyph->rect = R_ScrapAlloc (&font->scrap, width, height);
glyph->bearing = (vec2i_t) { g->bitmap_left, g->bitmap_top };
glyph->advance = g->advance.x;
glyph->charcode = *c;
Hash_AddElement (font->glyphmap, glyph);
copy_glypn (glyph, g);
}
return font;
}

View file

@ -39,12 +39,14 @@
#include "QF/draw.h"
#include "QF/hash.h"
#include "QF/progs.h"
#include "QF/quakefs.h"
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/ui/view.h"
#include "r_internal.h"
#include "r_font.h"
typedef struct {
pr_int_t width;
@ -332,6 +334,18 @@ bi_Draw_Height (progs_t *pr, void *_res)
R_INT (pr) = r_data->vid->conview->ylen;
}
static void
bi_Font_Load (progs_t *pr, void *_res)
{
const char *font_path = P_GSTRING (pr, 0);
int font_size = P_INT (pr, 1);
int *preload = (int *) P_GPOINTER (pr, 2);
QFile *font_file = QFS_FOpenFile (font_path);
rfont_t *font = R_FontLoad (font_file, font_size, preload);
(void)font;
}
static const char *
bi_draw_get_key (const void *p, void *unused)
{
@ -381,6 +395,8 @@ static builtin_t builtins[] = {
bi(Draw_Fill, 5, p(int), p(int), p(int), p(int), p(int)),
bi(Draw_Line, 5, p(int), p(int), p(int), p(int), p(int)),
bi(Draw_Crosshair, 5, p(int), p(int), p(int), p(int)),
bi(Font_Load, 3, p(string), p(int), p(ptr)),
{0}
};

View file

@ -57,6 +57,7 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include "QF/plugin/console.h"
#include "rua_internal.h"
#include "r_font.h"
#include "ruamoko/qwaq/qwaq.h"
@ -330,6 +331,8 @@ BI_Graphics_Init (progs_t *pr)
IN_Init ();
Mod_Init ();
R_Init ();
R_FontInit ();
R_Progs_Init (pr);
RUA_Game_Init (pr, thread->rua_security);
S_Progs_Init (pr);