Add initial sources.

This commit is contained in:
Josh Holtrop 2020-12-30 22:56:52 -05:00
commit 2c725d3cdd
2 changed files with 241 additions and 0 deletions

145
dft.c Normal file
View File

@ -0,0 +1,145 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#define round_up_26_6(val) (((val) + 63) >> 6u)
typedef struct
{
int32_t line_height;
int32_t baseline_offset;
FT_Face ft_face;
} dft_font_t;
typedef struct
{
uint8_t * bitmap;
int32_t width;
int32_t height;
int32_t left;
int32_t top;
int32_t advance;
FT_Glyph ft_glyph;
} dft_glyph_t;
static FT_Library ft_library_handle;
static bool ft_initialized;
static bool initialize_freetype()
{
if (ft_initialized)
{
return true;
}
if (FT_Init_FreeType(&ft_library_handle) != 0)
{
return false;
}
ft_initialized = true;
return true;
}
dft_glyph_t * dft_glyph_new(dft_font_t * dft_font, uint32_t char_code, int32_t outline_size)
{
FT_Glyph glyph;
FT_BitmapGlyph bitmap_glyph;
FT_UInt glyph_index = FT_Get_Char_Index(dft_font->ft_face, char_code);
/* Load the glyph to the face object. */
FT_Load_Glyph(dft_font->ft_face, glyph_index, FT_LOAD_NO_BITMAP);
FT_Get_Glyph(dft_font->ft_face->glyph, &glyph);
if (outline_size > 0)
{
FT_Stroker stroker;
FT_Stroker_New(ft_library_handle, &stroker);
FT_Stroker_Set(stroker, outline_size, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
FT_Glyph_StrokeBorder(&glyph, stroker, false, true);
}
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, true);
bitmap_glyph = (FT_BitmapGlyph)glyph;
int32_t width = bitmap_glyph->bitmap.width;
int32_t height = bitmap_glyph->bitmap.rows;
dft_glyph_t * dft_glyph = (dft_glyph_t *)malloc(sizeof(dft_glyph_t));
dft_glyph->ft_glyph = glyph;
dft_glyph->width = width;
dft_glyph->height = height;
dft_glyph->left = bitmap_glyph->left;
dft_glyph->top = bitmap_glyph->top;
dft_glyph->advance = round_up_26_6(dft_font->ft_face->glyph->advance.x);
size_t n_bytes = (size_t)(width * height);
dft_glyph->bitmap = (uint8_t *)malloc(n_bytes);
memcpy(dft_glyph->bitmap, bitmap_glyph->bitmap.buffer, n_bytes);
return dft_glyph;
}
void dft_glyph_free(dft_glyph_t * dft_glyph)
{
FT_Done_Glyph(dft_glyph->ft_glyph);
free(dft_glyph->bitmap);
free(dft_glyph);
}
static inline void build_font_metrics(dft_font_t * dft_font)
{
static const char load_chars[] = "Mg_^";
int max_top = INT_MIN;
int min_bottom = INT_MAX;
for (size_t i = 0u; i < (sizeof(load_chars) - 1u); i++)
{
dft_glyph_t * dft_glyph = dft_glyph_new(dft_font, load_chars[i], 0);
if (dft_glyph->top > max_top)
{
max_top = dft_glyph->top;
}
int bottom = dft_glyph->top - dft_glyph->height;
if (bottom < min_bottom)
{
min_bottom = bottom;
}
}
dft_font->line_height = round_up_26_6(dft_font->ft_face->size->metrics.height);
dft_font->baseline_offset = (dft_font->line_height - (max_top - min_bottom)) / 2 - min_bottom;
}
dft_font_t * dft_font_new(const uint8_t * file_data, uint32_t file_size, int font_size)
{
if (!initialize_freetype())
{
return NULL;
}
FT_Face ft_face;
if (FT_New_Memory_Face(ft_library_handle, file_data, file_size, 0, &ft_face) != 0)
{
return NULL;
}
dft_font_t * dft_font = (dft_font_t *)malloc(sizeof(dft_font_t));
dft_font->ft_face = ft_face;
FT_Set_Pixel_Sizes(ft_face, 0, font_size);
build_font_metrics(dft_font);
return dft_font;
}
void dft_font_free(dft_font_t * dft_font)
{
FT_Done_Face(dft_font->ft_face);
free(dft_font);
}

96
package.d Normal file
View File

@ -0,0 +1,96 @@
module dft;
import std.file;
private struct dft_font_t
{
int line_height;
int baseline_offset;
};
private struct dft_glyph_t
{
ubyte * bitmap;
int width;
int height;
int left;
int top;
int advance;
};
private extern(C) dft_glyph_t * dft_glyph_new(dft_font_t * dft_font, uint char_code, int outline_size);
private extern(C) void dft_glyph_free(dft_glyph_t * dft_glyph);
private extern(C) dft_font_t * dft_font_new(const ubyte * file_data, uint file_size, int font_size);
private extern(C) void dft_font_free(dft_font_t * dft_font);
class Font
{
class Glyph
{
dft_glyph_t * m_dft_glyph;
private this(Font font, uint char_code, int outline_size)
{
m_dft_glyph = dft_glyph_new(font.m_dft_font, char_code, outline_size);
}
~this()
{
dft_glyph_free(m_dft_glyph);
}
@property int width()
{
return m_dft_glyph.width;
}
@property int height()
{
return m_dft_glyph.height;
}
@property int left()
{
return m_dft_glyph.left;
}
@property int top()
{
return m_dft_glyph.top;
}
@property const(ubyte)[] bitmap()
{
int n_bytes = width * height;
return m_dft_glyph.bitmap[0..n_bytes];
}
}
dft_font_t * m_dft_font;
this(const(ubyte)[] file_data, int font_size)
{
m_dft_font = dft_font_new(file_data.ptr, cast(uint)file_data.length, font_size);
}
this(string file_name, int font_size)
{
const(ubyte)[] file_data = cast(const(ubyte)[])std.file.read(file_name);
this(file_data, font_size);
}
~this()
{
dft_font_free(m_dft_font);
}
@property int line_height()
{
return m_dft_font.line_height;
}
@property int baseline_offset()
{
return m_dft_font.baseline_offset;
}
}