Browse Source

Structure a bit more like a library

master
A.Olokhtonov 3 years ago
parent
commit
d63a847eab
  1. 579
      main.c
  2. 17
      ttf-parse.c
  3. 279
      ttf-rasterize.c
  4. 154
      ttf.h

579
main.c

@ -44,165 +44,6 @@ typedef uint8_t u8; @@ -44,165 +44,6 @@ typedef uint8_t u8;
typedef float f32;
typedef double f64;
/************* TTF *************/
struct v2 {
int x;
int y;
};
struct v2u32 {
u32 x;
u32 y;
};
struct v2f {
f32 x;
f32 y;
};
struct line {
struct v2f a;
struct v2f b;
};
struct line_contour {
int ncontours;
int from[MAX_CONTOURS];
struct line *data;
};
struct intersection {
f32 x;
int dir;
};
enum rgb_channel {
RED = 0x000000FF,
GREEN = 0x0000FF00,
BLUE = 0x00FF0000,
};
struct font_buffer {
u8 *data;
u64 offset;
u64 size;
};
struct font_directory {
u32 cmap_offset;
u32 head_offset;
u32 hhea_offset;
u32 loca_offset;
u32 glyf_offset;
u32 hmtx_offset;
u32 maxp_offset;
u32 post_offset;
u32 cvt_offset;
u32 cvt_size;
u32 prep_offset;
u32 prep_size;
u32 fpgm_offset;
u32 fpgm_size;
};
union glyph_flag {
struct {
u8 on_curve : 1;
u8 x_short : 1;
u8 y_short : 1;
u8 repeat : 1;
u8 x_short_pos : 1;
u8 y_short_pos : 1;
u8 reserved1 : 1;
u8 reserved2 : 1;
};
u8 flag;
};
enum compund_glyph_flag {
ARG_1_AND_2_ARE_WORDS = 0x1,
ARGS_ARE_XY_VALUES = 0x2,
ROUND_XY_TO_GRID = 0x4,
WE_HAVE_A_SCALE = 0x8,
MORE_COMPONENTS = 0x20,
WE_HAVE_AN_X_AND_Y_SCALE = 0x40,
WE_HAVE_A_TWO_BY_TWO = 0x80,
WE_HAVE_INSTRUCTIONS = 0x100,
USE_MY_METRICS = 0x200,
OVERLAP_COMPOUND = 0x400
};
struct maxp_table {
u16 max_component_points;
u16 max_component_contours;
u16 max_storage;
u16 max_fdefs;
};
struct head_table {
int itl_format;
int units_per_em;
};
struct hhea_table {
int ascent;
int descent;
int line_gap;
int max_advance;
};
struct glyph_point {
s16 x;
s16 y;
bool on_curve;
};
struct glyph_segment {
bool is_curve;
struct v2f p0;
struct v2f p1;
struct v2f p2;
};
struct glyph {
s16 xmin, ymin;
s16 xmax, ymax;
s32 baseline;
u16 advance;
s16 lsb;
u16 ncontours;
u16 *end_pts_of_contours;
struct glyph_point *points;
};
struct ttf_font {
struct font_buffer file;
struct maxp_table maxp;
struct head_table head;
struct hhea_table hhea;
s16 *cvt;
int cmap_format;
int is_monospace;
struct font_directory dir;
struct ttf_function *functions;
u32 *storage;
char *name;
};
/*******************************/
static int
clamp_u32(u32 val, u32 cap)
{
@ -221,7 +62,6 @@ abs_f32(f32 v) @@ -221,7 +62,6 @@ abs_f32(f32 v)
static int
round_f32(f32 v)
{
#if 1
int towards_zero = (int) v;
f32 diff = abs_f32(v - towards_zero);
@ -230,9 +70,6 @@ round_f32(f32 v) @@ -230,9 +70,6 @@ round_f32(f32 v)
} else {
return(towards_zero);
}
#else
return(v);
#endif
}
static int
@ -245,421 +82,17 @@ ceil_f32(f32 v) @@ -245,421 +82,17 @@ ceil_f32(f32 v)
return(trunc + 1);
}
#include "ttf.h"
#include "ttf_engine.c"
#include "ttf2.c"
#include "ttf-parse.c"
#include "ttf-rasterize.c"
static Display *display;
static Window window;
static GC default_gc;
static XImage* xwindow_buffer;
static int
scanline_intersects_line(f32 y, struct v2f p0, struct v2f p1, f32 lasty, f32 *vx)
{
bool goes_up = (p0.y > p1.y);
f32 t1 = (y - p0.y) / (p1.y - p0.y); /* NOTE(aolo2): no horizontal lines by design */
if (t1 == 0) {
f32 x1 = p0.x + (p1.x - p0.x) * t1;
if ((lasty < p0.y) && (p0.y > p1.y)) return(0);
if ((lasty > p0.y) && (p0.y < p1.y)) return(0);
int result = (goes_up ? 1 : -1);
*vx = x1;
return(result);
}
if (0 < t1 && t1 < 1.0f) {
f32 x1 = p0.x + (p1.x - p0.x) * t1;
*vx = x1;
int result = (goes_up ? 1 : -1);
return(result);
}
return(0);
}
static void
render_line(struct v2 from, struct v2 to, u32 *pixels, int width, int height, u32 color)
{
if (from.x >= width) {
from.x = width - 1;
}
if (to.x >= width) {
to.x = width - 1;
}
if (from.y >= height) {
from.y = height - 1;
}
if (to.y >= height) {
to.y = height - 1;
}
if (from.y == to.y) {
if (to.x < from.x) {
int tmp = to.x;
to.x = from.x;
from.x = tmp;
}
u32 *out = pixels + width * from.y + from.x;
// printf("%ld %ld -> %ld %ld\n", from.x, from.y, to.x, to.y);
for (int x = from.x; x <= to.x; ++x) {
// printf("%d\n", x);
*out = color;
++out;
}
} else if (from.x == to.x) {
if (to.y < from.y) {
int tmp = to.y;
to.y = from.y;
from.y = tmp;
}
u32 *out = pixels + width * from.y + from.x;
//printf("%ld %ld -> %ld %ld\n", from.x, from.y, to.x, to.y);
for (int y = from.y; y <= to.y; ++y) {
out = pixels + width * y + from.x;
*out = color;
}
} else {
int x0 = from.x;
int y0 = from.y;
int x1 = to.x;
int y1 = to.y;
int dx = abs(x1 - x0);
int sx = (x0 < x1 ? 1 : -1);
int dy = -abs(y1 - y0);
int sy = (y0 < y1 ? 1 : -1);
int err = dx+dy;
while (0 <= x0 && x0 < width && 0 <= y0 && y0 < height) {
u32 *out = pixels + width * y0 + x0;
*out = color;
if (x0 == x1 && y0 == y1) {
break;
}
int e2 = 2 * err;
if (e2 >= dy) {
err += dy;
x0 += sx;
}
if (e2 <= dx) {
err += dx;
y0 += sy;
}
}
}
}
static void
render_grid(int x_step, int y_step, u32 *pixels, int width, int height)
{
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (x % x_step == 0 || y % y_step == 0) {
pixels[y * width + x] = 0xFFEEEEE;
}
}
}
}
static int
intersect_glyph(struct line_contour *lines, f32 y, struct intersection *intersections)
{
int nints = 0;
for (int c = 0; c < lines->ncontours; ++c) {
int from = lines->from[c];
int to = lines->from[c + 1];
for (int i = from; i < to; ++i) {
int lasti = (i > from ? i - 1 : to - 1);
f32 lasty = lines->data[lasti].a.y;
f32 vx;
int r = scanline_intersects_line(y, lines->data[i].a, lines->data[i].b, lasty, &vx);
if (r) {
intersections[nints].x = vx;
intersections[nints].dir = r;
++nints;
}
}
}
return(nints);
}
static void
_D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int height)
{
int points_from = 0;
for (int c = 0; c < g.ncontours; ++c) {
for (int p = points_from; p < g.end_pts_of_contours[c] + 1; ++p) {
struct glyph_point gp = g.points[p];
int x1 = round_f32((gp.x - g.xmin) * scale);
int y1 = round_f32(gp.y * scale);
int next = p + 1;
if (p == g.end_pts_of_contours[c]) {
next = points_from;
}
int x2 = round_f32((g.points[next].x - g.xmin) * scale);
int y2 = round_f32(g.points[next].y * scale);
render_line((struct v2) {x1, y1}, (struct v2) {x2, y2}, pixels, width, height, 0xFFFF00FF);
//printf("%d %d\n", g.points[p].x, g.points[p].y);
//XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
if (gp.on_curve) {
pixels[y1 * width + x1] = 0xFF0000FF;
} else {
pixels[y1 * width + x1] = 0xFFFFFF00;
}
}
points_from = g.end_pts_of_contours[c] + 1;
}
}
static void
sort_intersections(struct intersection *intersections, int size)
{
bool swapped = true;
while (swapped) {
swapped = false;
for (int i = 0; i < size - 1; ++i) {
f32 x1 = intersections[i].x;
f32 x2 = intersections[i + 1].x;
if (x1 > x2) {
struct intersection tmp = intersections[i];
intersections[i] = intersections[i + 1];
intersections[i + 1] = tmp;
swapped = true;
}
}
}
}
static void
render_glyph(struct glyph g, int px_size, struct line_contour *lines,
f32 scale, u32 *pixels, int width, int at_x, int at_y)
{
int oversample_y = 4;
if (px_size <= 12) {
oversample_y = 8;
}
f32 oversample_step = 1.0f / (oversample_y + 1);
f32 oversample_norm = 1.0f / oversample_y;
int gwidth = ceil_f32((g.xmax - g.xmin) * scale);
int gheight = px_size;
struct intersection *intersections = malloc(lines->from[lines->ncontours] * sizeof(struct intersection));
f32 *accumulator = calloc(1, gwidth * gheight * sizeof(f32));
for (int y = 0; y < gheight; ++y) {
for (int yy = 1; yy <= oversample_y; ++yy) {
u32 ncross = intersect_glyph(lines, y + oversample_step * yy, intersections);
if (ncross) {
sort_intersections(intersections, ncross);
int state = 0;
for (u32 i = 0; i < ncross - 1; ++i) {
struct intersection inter = intersections[i];
struct intersection next_inter = intersections[i + 1];
state += inter.dir;
if (state != 0) {
f32 x0 = inter.x;
f32 x1 = next_inter.x;
int x_from = x0;
int x_to = (x1 > gwidth - 1 ? gwidth - 1 : x1);
f32 start_brightness = (x_from + 1 - x0);
f32 end_brightness = (x1 - x_to);
for (int x = x_from + 1; x < x_to; ++x) {
accumulator[y * gwidth + x] += oversample_norm;
}
accumulator[y * gwidth + x_from] += start_brightness * oversample_norm;
accumulator[y * gwidth + x_to] += end_brightness * oversample_norm;
}
}
}
}
}
for (int y = 0; y < gheight; ++y) {
for (int x = 0; x < gwidth; ++x) {
//printf(" %.2f", accumulator[y * gwidth + x]);
u32 brightness = clamp_u32(accumulator[y * gwidth + x] * 255.99f, 255);
u32 white = 0xFF000000 | brightness << 16 | brightness << 8 | brightness;
if (brightness > 0) {
pixels[(at_y + (gheight - 1 - y)) * width + (at_x + x)] = white;
} else {
//pixels[(at_y + (gheight - 1 - y)) * width + (at_x + x)] = 0xFFFF0000;
}
}
}
free(accumulator);
//exit(1);
free(intersections);
}
static void
outline_to_lines(struct glyph g, f32 scale, int max_descent, struct line_contour *dest, int *cnt)
{
int nlines = 0;
int points_from = 0;
int curve_segments = 5;
for (int c = 0; c < g.ncontours; ++c) {
for (int p = points_from; p < g.end_pts_of_contours[c] + 1; ++p) {
struct glyph_point gp = g.points[p];
int nexti = (p + 1 < g.end_pts_of_contours[c] + 1 ? p + 1 : points_from);
struct glyph_point nextgp = g.points[nexti];
if (p == points_from && !gp.on_curve) {
continue;
}
f32 x1 = gp.x * scale;
f32 y1 = (gp.y - g.baseline - max_descent) * scale;
f32 x2 = nextgp.x * scale;
f32 y2 = (nextgp.y - g.baseline - max_descent) * scale;
if (nextgp.on_curve) {
if (gp.y != nextgp.y) {
if (dest->data) {
dest->data[nlines].a = (struct v2f) { x1, y1 };
dest->data[nlines].b = (struct v2f) { x2, y2 };
}
++nlines;
}
} else {
int nextnexti = (nexti + 1 < g.end_pts_of_contours[c] + 1 ? nexti + 1 : points_from);
struct glyph_point nextnextgp = g.points[nextnexti];
f32 x3 = nextnextgp.x * scale;
f32 y3 = (nextnextgp.y - g.baseline - max_descent) * scale;
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */
f32 t_step = 1.0f / curve_segments;
f32 x_prev = x1;
f32 y_prev = y1;
/* s = 1 for exact beginning */
for (int s = 1; s <= curve_segments; ++s) {
f32 t_now = t_step * s;
f32 x_now;
f32 y_now;
if (s < curve_segments) {
x_now = x3 * t_now * t_now
+ x2 * 2.0f * t_now * (1.0f - t_now)
+ x1 * (1.0f - t_now) * (1.0f - t_now);
y_now = y3 * t_now * t_now
+ y2 * 2.0f * t_now * (1.0f - t_now)
+ y1 * (1.0f - t_now) * (1.0f - t_now);
} else {
/* For exact match between neighbours */
x_now = x3;
y_now = y3;
}
if (abs_f32(y_now - y_prev) > F32EPS) {
if (dest->data) {
dest->data[nlines].a = (struct v2f) { x_prev, y_prev };
dest->data[nlines].b = (struct v2f) { x_now, y_now };
}
++nlines;
}
x_prev = x_now;
y_prev = y_now;
}
++p;
}
}
dest->from[c + 1] = nlines;
points_from = g.end_pts_of_contours[c] + 1;
}
dest->ncontours = g.ncontours;
if (cnt) {
*cnt = nlines;
}
}
static void
render_utf_string(struct ttf_font font, int px_size, u32 *pixels, u32 width, wchar_t *string, int at_x, int at_y)
{
u32 offset_x = at_x;
u32 offset_y = at_y;
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
u32 len = wcslen(string);
for (u32 i = 0; i < len; ++i) {
u16 codepoint = string[i];
if (codepoint != ' ') {
struct glyph g = get_outline(&font, codepoint);
//exit(0);
struct line_contour lines = { 0 };
int nlines = 0;
outline_to_lines(g, scale, font.hhea.descent, &lines, &nlines);
lines.data = malloc(nlines * sizeof(struct line));
outline_to_lines(g, scale, font.hhea.descent, &lines, 0);
render_glyph(g, px_size, &lines, scale, pixels, width, offset_x + g.lsb * scale, offset_y);
offset_x += ceil_f32(scale * g.advance);
free(lines.data);
} else {
offset_x += px_size / 3;
}
//XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
//sleep(1);
}
}
int
main(int argc, char **argv)
{
@ -730,9 +163,9 @@ main(int argc, char **argv) @@ -730,9 +163,9 @@ main(int argc, char **argv)
//render_utf_string(font, 18, pixels, width, L"The quick brown fox jumps over the lazy dog", 100, 150);
//render_utf_string(font, 12, pixels, width, L"This text is seriously small", 100, at); at += 12;
//render_utf_string(font, 13, pixels, width, L"This text is seriously small", 100, at); at += 13;
render_utf_string(font, 14, pixels, width, L"This text is seriously small", 100, at); at += 14;
//render_utf_string(font, 15, pixels, width, L"This text is seriously small", 100, at); at += 14;
render_utf_string(font, 26, pixels, width, L"memset(pixels, 0x00, width * height * 4);", 10, at); at += 24;
render_utf_string(font, 12, pixels, width, L"This text is seriously small", 100, at); at += 12;
render_utf_string(font, 18, pixels, width, L"aolo2@avx:~/Documents/code/ttf-test (master) $", 100, at); at += 20;
render_utf_string(font, 26, pixels, width, L"render_utf_string(font, 32, pixels, width, string3, 10 + w1 + w2, at);", 10, at); at += 24;
render_utf_string(font, 24, pixels, width, L"The quick brown fox jumps over the lazy dog", 10, at); at += 24;
wchar_t *string1 = L"iiiiiiiiiiiiiiiiiii";

17
ttf2.c → ttf-parse.c

@ -1463,18 +1463,26 @@ get_hmtx(struct ttf_font *font, u32 glyph_index, struct glyph *dest) @@ -1463,18 +1463,26 @@ get_hmtx(struct ttf_font *font, u32 glyph_index, struct glyph *dest)
dest->lsb = read_be16s(&font_file);
}
static int
get_codepoint_width(struct ttf_font *font, f32 scale, u16 codepoint)
{
struct glyph g = { 0 };
u32 glyph_index = get_glyph_index(font, codepoint);
get_hmtx(font, glyph_index, &g);
int result = ceil_f32(scale * g.advance);
return(result);
}
static int
get_string_width(struct ttf_font *font, int px_size, wchar_t *string, int length)
{
int result = 0;
struct glyph g = { 0 };
f32 scale = (f32) px_size / ((f32) (font->hhea.ascent - font->hhea.descent));
for (int i = 0; i < length; ++i) {
u16 codepoint = string[i];
u32 glyph_index = get_glyph_index(font, codepoint);
get_hmtx(font, glyph_index, &g);
result += ceil_f32(scale * g.advance); // NOTE(aolo2): ceil each time because that's what the rasterizing code does
// NOTE(aolo2): advance is rounded up for each glyph (and not once in the end), because that's what the rasterizer does
result += get_codepoint_width(font, scale, codepoint);
}
return(result);
@ -1499,6 +1507,7 @@ get_outline(struct ttf_font *font, u16 codepoint) @@ -1499,6 +1507,7 @@ get_outline(struct ttf_font *font, u16 codepoint)
}
result.baseline = - (int) result.ymin;
result.lsb += xmin;
result.xmin = 0;
result.xmax -= xmin;
result.ymin = 0;

279
ttf-rasterize.c

@ -0,0 +1,279 @@ @@ -0,0 +1,279 @@
static int
scanline_intersects_line(f32 y, struct v2f p0, struct v2f p1, f32 lasty, f32 *vx)
{
bool goes_up = (p0.y > p1.y);
f32 t1 = (y - p0.y) / (p1.y - p0.y); /* NOTE(aolo2): no horizontal lines by design */
if (t1 == 0) {
f32 x1 = p0.x + (p1.x - p0.x) * t1;
if ((lasty < p0.y) && (p0.y > p1.y)) return(0);
if ((lasty > p0.y) && (p0.y < p1.y)) return(0);
int result = (goes_up ? 1 : -1);
*vx = x1;
return(result);
}
if (0 < t1 && t1 < 1.0f) {
f32 x1 = p0.x + (p1.x - p0.x) * t1;
*vx = x1;
int result = (goes_up ? 1 : -1);
return(result);
}
return(0);
}
static int
intersect_glyph(struct line_contour *lines, f32 y, struct intersection *intersections)
{
int nints = 0;
for (int c = 0; c < lines->ncontours; ++c) {
int from = lines->from[c];
int to = lines->from[c + 1];
for (int i = from; i < to; ++i) {
int lasti = (i > from ? i - 1 : to - 1);
f32 lasty = lines->data[lasti].a.y;
f32 vx;
int r = scanline_intersects_line(y, lines->data[i].a, lines->data[i].b, lasty, &vx);
if (r) {
intersections[nints].x = vx;
intersections[nints].dir = r;
++nints;
}
}
}
return(nints);
}
static void
sort_intersections(struct intersection *intersections, int size)
{
bool swapped = true;
while (swapped) {
swapped = false;
for (int i = 0; i < size - 1; ++i) {
f32 x1 = intersections[i].x;
f32 x2 = intersections[i + 1].x;
if (x1 > x2) {
struct intersection tmp = intersections[i];
intersections[i] = intersections[i + 1];
intersections[i + 1] = tmp;
swapped = true;
}
}
}
}
static void
render_glyph(struct glyph g, int px_size, struct line_contour *lines,
f32 scale, u32 *pixels, int width, int at_x, int at_y)
{
int oversample_y = 4;
if (px_size <= 12) {
oversample_y = 8;
}
f32 oversample_step = 1.0f / (oversample_y + 1);
f32 oversample_norm = 1.0f / oversample_y;
int gwidth = ceil_f32((g.xmax - g.xmin + g.lsb) * scale);
int gheight = px_size;
struct intersection *intersections = malloc(lines->from[lines->ncontours] * sizeof(struct intersection));
f32 *accumulator = calloc(1, gwidth * gheight * sizeof(f32));
for (int y = 0; y < gheight; ++y) {
for (int yy = 1; yy <= oversample_y; ++yy) {
u32 ncross = intersect_glyph(lines, y + oversample_step * yy, intersections);
if (ncross) {
sort_intersections(intersections, ncross);
int state = 0;
for (u32 i = 0; i < ncross - 1; ++i) {
struct intersection inter = intersections[i];
struct intersection next_inter = intersections[i + 1];
state += inter.dir;
if (state != 0) {
f32 x0 = inter.x;
f32 x1 = next_inter.x;
int x_from = x0;
int x_to = (x1 > gwidth - 1 ? gwidth - 1 : x1);
f32 start_brightness = (x_from + 1 - x0);
f32 end_brightness = (x1 - x_to);
for (int x = x_from + 1; x < x_to; ++x) {
accumulator[y * gwidth + x] += oversample_norm;
}
accumulator[y * gwidth + x_from] += start_brightness * oversample_norm;
accumulator[y * gwidth + x_to] += end_brightness * oversample_norm;
}
}
}
}
}
for (int y = 0; y < gheight; ++y) {
for (int x = 0; x < gwidth; ++x) {
//printf(" %.2f", accumulator[y * gwidth + x]);
u32 brightness = clamp_u32(accumulator[y * gwidth + x] * 255.99f, 255);
u32 white = 0xFF000000 | brightness << 16 | brightness << 8 | brightness;
if (brightness > 0) {
pixels[(at_y + (gheight - 1 - y)) * width + (at_x + x)] = white;
} else {
//pixels[(at_y + (gheight - 1 - y)) * width + (at_x + x)] = 0xFFFF0000;
}
}
}
free(accumulator);
//exit(1);
free(intersections);
}
static void
outline_to_lines(struct glyph g, f32 scale, int max_descent, struct line_contour *dest, int *cnt)
{
int nlines = 0;
int points_from = 0;
int curve_segments = 5;
for (int c = 0; c < g.ncontours; ++c) {
for (int p = points_from; p < g.end_pts_of_contours[c] + 1; ++p) {
struct glyph_point gp = g.points[p];
int nexti = (p + 1 < g.end_pts_of_contours[c] + 1 ? p + 1 : points_from);
struct glyph_point nextgp = g.points[nexti];
if (p == points_from && !gp.on_curve) {
continue;
}
f32 x1 = (gp.x + g.lsb) * scale;
f32 y1 = (gp.y - g.baseline - max_descent) * scale;
f32 x2 = (nextgp.x + g.lsb) * scale;
f32 y2 = (nextgp.y - g.baseline - max_descent) * scale;
if (nextgp.on_curve) {
if (gp.y != nextgp.y) {
if (dest->data) {
dest->data[nlines].a = (struct v2f) { x1, y1 };
dest->data[nlines].b = (struct v2f) { x2, y2 };
}
++nlines;
}
} else {
int nextnexti = (nexti + 1 < g.end_pts_of_contours[c] + 1 ? nexti + 1 : points_from);
struct glyph_point nextnextgp = g.points[nextnexti];
f32 x3 = (nextnextgp.x + g.lsb) * scale;
f32 y3 = (nextnextgp.y - g.baseline - max_descent) * scale;
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */
f32 t_step = 1.0f / curve_segments;
f32 x_prev = x1;
f32 y_prev = y1;
/* s = 1 for exact beginning */
for (int s = 1; s <= curve_segments; ++s) {
f32 t_now = t_step * s;
f32 x_now;
f32 y_now;
if (s < curve_segments) {
x_now = x3 * t_now * t_now
+ x2 * 2.0f * t_now * (1.0f - t_now)
+ x1 * (1.0f - t_now) * (1.0f - t_now);
y_now = y3 * t_now * t_now
+ y2 * 2.0f * t_now * (1.0f - t_now)
+ y1 * (1.0f - t_now) * (1.0f - t_now);
} else {
/* For exact match between neighbours */
x_now = x3;
y_now = y3;
}
if (abs_f32(y_now - y_prev) > F32EPS) {
if (dest->data) {
dest->data[nlines].a = (struct v2f) { x_prev, y_prev };
dest->data[nlines].b = (struct v2f) { x_now, y_now };
}
++nlines;
}
x_prev = x_now;
y_prev = y_now;
}
++p;
}
}
dest->from[c + 1] = nlines;
points_from = g.end_pts_of_contours[c] + 1;
}
dest->ncontours = g.ncontours;
if (cnt) {
*cnt = nlines;
}
}
static void
render_utf_string(struct ttf_font font, int px_size, u32 *pixels, u32 width, wchar_t *string, int at_x, int at_y)
{
u32 offset_x = at_x;
u32 offset_y = at_y;
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
u32 len = wcslen(string);
for (u32 i = 0; i < len; ++i) {
u16 codepoint = string[i];
if (codepoint != ' ') {
struct glyph g = get_outline(&font, codepoint);
//exit(0);
struct line_contour lines = { 0 };
int nlines = 0;
outline_to_lines(g, scale, font.hhea.descent, &lines, &nlines);
lines.data = malloc(nlines * sizeof(struct line));
outline_to_lines(g, scale, font.hhea.descent, &lines, 0);
render_glyph(g, px_size, &lines, scale, pixels, width, offset_x, offset_y);
offset_x += ceil_f32(scale * g.advance);
free(lines.data);
} else {
int space_advance = get_codepoint_width(&font, scale, codepoint);
offset_x += space_advance;
}
//XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
//sleep(1);
}
}

154
ttf.h

@ -0,0 +1,154 @@ @@ -0,0 +1,154 @@
struct v2 {
int x;
int y;
};
struct v2u32 {
u32 x;
u32 y;
};
struct v2f {
f32 x;
f32 y;
};
struct line {
struct v2f a;
struct v2f b;
};
struct line_contour {
int ncontours;
int from[MAX_CONTOURS];
struct line *data;
};
struct intersection {
f32 x;
int dir;
};
enum rgb_channel {
RED = 0x000000FF,
GREEN = 0x0000FF00,
BLUE = 0x00FF0000,
};
struct font_buffer {
u8 *data;
u64 offset;
u64 size;
};
struct font_directory {
u32 cmap_offset;
u32 head_offset;
u32 hhea_offset;
u32 loca_offset;
u32 glyf_offset;
u32 hmtx_offset;
u32 maxp_offset;
u32 post_offset;
u32 cvt_offset;
u32 cvt_size;
u32 prep_offset;
u32 prep_size;
u32 fpgm_offset;
u32 fpgm_size;
};
union glyph_flag {
struct {
u8 on_curve : 1;
u8 x_short : 1;
u8 y_short : 1;
u8 repeat : 1;
u8 x_short_pos : 1;
u8 y_short_pos : 1;
u8 reserved1 : 1;
u8 reserved2 : 1;
};
u8 flag;
};
enum compund_glyph_flag {
ARG_1_AND_2_ARE_WORDS = 0x1,
ARGS_ARE_XY_VALUES = 0x2,
ROUND_XY_TO_GRID = 0x4,
WE_HAVE_A_SCALE = 0x8,
MORE_COMPONENTS = 0x20,
WE_HAVE_AN_X_AND_Y_SCALE = 0x40,
WE_HAVE_A_TWO_BY_TWO = 0x80,
WE_HAVE_INSTRUCTIONS = 0x100,
USE_MY_METRICS = 0x200,
OVERLAP_COMPOUND = 0x400
};
struct maxp_table {
u16 max_component_points;
u16 max_component_contours;
u16 max_storage;
u16 max_fdefs;
};
struct head_table {
int itl_format;
int units_per_em;
};
struct hhea_table {
int ascent;
int descent;
int line_gap;
int max_advance;
};
struct glyph_point {
s16 x;
s16 y;
bool on_curve;
};
struct glyph_segment {
bool is_curve;
struct v2f p0;
struct v2f p1;
struct v2f p2;
};
struct glyph {
s16 xmin, ymin;
s16 xmax, ymax;
s32 baseline;
u16 advance;
s16 lsb;
u16 ncontours;
u16 *end_pts_of_contours;
struct glyph_point *points;
};
struct ttf_font {
struct font_buffer file;
struct maxp_table maxp;
struct head_table head;
struct hhea_table hhea;
s16 *cvt;
int cmap_format;
int is_monospace;
struct font_directory dir;
struct ttf_function *functions;
u32 *storage;
char *name;
};
Loading…
Cancel
Save