You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
657 lines
17 KiB
657 lines
17 KiB
4 years ago
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdbool.h>
|
||
|
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#include <X11/Xlib.h>
|
||
|
#include <X11/Xutil.h>
|
||
|
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
#define ASSERT(expr) if (!expr) { fprintf(stderr, "[ASSERT] Assertion fail %s:%d\n", __FILE__, __LINE__); abort(); }
|
||
|
|
||
|
#define MAX_INTERSECTIONS 16
|
||
|
#define F32EPS 1e-5f
|
||
|
#define MAX_CONTOURS 16
|
||
|
|
||
|
#define PER_PIXEL 0
|
||
|
#define PER_ROW 0
|
||
|
#define DEBUG_SHOW_POINTS 1
|
||
|
|
||
|
/*
|
||
|
int total_hits = 0;
|
||
|
for (int yy = 1; yy <= oversample_y; ++yy) {
|
||
|
for (int xx = 1; xx <= oversample_x; ++xx) {
|
||
|
u32 ncross = intersect_glyph(g, scale, x + norm_x * xx , y + norm_y * yy, width);
|
||
|
if (ncross) {
|
||
|
++total_hits;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (total_hits) {
|
||
|
u32 brightness = (256 - total_hits * 256 / (oversample_x * oversample_y)) * 0.99f;
|
||
|
pixels[(y - baseline_correction) * width + x] = 0xFF000000 | brightness << 16 | brightness << 8 | brightness;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
typedef int64_t s64;
|
||
|
typedef int32_t s32;
|
||
|
typedef int16_t s16;
|
||
|
typedef int8_t s8;
|
||
|
|
||
|
typedef uint64_t u64;
|
||
|
typedef uint32_t u32;
|
||
|
typedef uint16_t u16;
|
||
|
typedef uint8_t u8;
|
||
|
|
||
|
typedef float f32;
|
||
|
typedef double f64;
|
||
|
|
||
|
|
||
|
/************* TTF *************/
|
||
|
|
||
|
struct v2 {
|
||
|
int x;
|
||
|
int 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 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;
|
||
|
};
|
||
|
|
||
|
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;
|
||
|
};
|
||
|
|
||
|
struct head_table {
|
||
|
int itl_format;
|
||
|
int units_per_em;
|
||
|
};
|
||
|
|
||
|
struct hhea_table {
|
||
|
int ascent;
|
||
|
int descent;
|
||
|
};
|
||
|
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
|
||
|
char *name;
|
||
|
|
||
|
int cmap_format;
|
||
|
|
||
|
int glyf_offset;
|
||
|
int loca_offset;
|
||
|
int cmap_offset;
|
||
|
int hmtx_offset;
|
||
|
};
|
||
|
|
||
|
/*******************************/
|
||
|
|
||
|
|
||
|
#include "ttf2.c"
|
||
|
|
||
|
static Display *display;
|
||
|
static Window window;
|
||
|
static GC default_gc;
|
||
|
static XImage* xwindow_buffer;
|
||
|
|
||
|
static f32
|
||
|
abs_f32(f32 v)
|
||
|
{
|
||
|
f32 result = (v > 0 ? v : -v);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
static f32
|
||
|
round_f32(f32 v)
|
||
|
{
|
||
|
return(v);
|
||
|
|
||
|
#if 0
|
||
|
int towards_zero = (int) v;
|
||
|
f32 diff = abs_f32(v - towards_zero);
|
||
|
|
||
|
if (diff >= 0.5f) {
|
||
|
return(v > 0 ? towards_zero + 1 : towards_zero - 1);
|
||
|
} else {
|
||
|
return(towards_zero);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
scanline_intersects_line(f32 x, f32 y, struct v2f p0, struct v2f p1, f32 lasty)
|
||
|
{
|
||
|
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 (x1 > x) {
|
||
|
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);
|
||
|
return(result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 < t1 && t1 < 1.0f) {
|
||
|
f32 x1 = p0.x + (p1.x - p0.x) * t1;
|
||
|
if (x1 > x) {
|
||
|
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 x, f32 y)
|
||
|
{
|
||
|
int result = 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;
|
||
|
int r = scanline_intersects_line(x, y, lines->data[i].a, lines->data[i].b, lasty);
|
||
|
result += r;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
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
|
||
|
render_glyph(struct glyph g, struct line_contour *lines,
|
||
|
struct ttf_font font, int px_size, u32 *pixels, int width, int height)
|
||
|
{
|
||
|
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
|
||
|
//int npoints = g.end_pts_of_contours[g.ncontours - 1] + 1;
|
||
|
|
||
|
if (g.advance < 0) {
|
||
|
g.advance *= -1;
|
||
|
}
|
||
|
|
||
|
int x0 = 0; // g.xmin * scale;
|
||
|
|
||
|
int gwidth = (g.xmax - g.xmin) * scale + 2;
|
||
|
int gheight = (g.ymax - g.ymin) * scale + 2;
|
||
|
|
||
|
pixels = pixels + width * 100 + 100;
|
||
|
|
||
|
#if 1
|
||
|
for (int y = 0; y < gheight; ++y) {
|
||
|
|
||
|
//u32 ncross = intersect_glyph(g, scale, x0 - 999.0f, y + 0.5f, width, intersections, &nints);
|
||
|
|
||
|
//if (ncross) {
|
||
|
//continue;
|
||
|
//}
|
||
|
|
||
|
for (int x = x0; x < x0 + gwidth; ++x) {
|
||
|
u32 ncross = intersect_glyph(lines, x + 0.5f, y + 0.5f);
|
||
|
if (ncross) {
|
||
|
pixels[y * width + x] = 0x00;
|
||
|
} else {
|
||
|
pixels[y * width + x] = 0xFFFF0000;
|
||
|
}
|
||
|
|
||
|
#if PER_PIXEL
|
||
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if PER_ROW
|
||
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
|
||
|
#endif
|
||
|
}
|
||
|
#else
|
||
|
int oversample_x = 4;
|
||
|
int oversample_y = 4;
|
||
|
f32 norm_x = 1.0f / (oversample_x + 1);
|
||
|
f32 norm_y = 1.0f / (oversample_y + 1);
|
||
|
int nints;
|
||
|
|
||
|
for (int y = 0; y < gheight; ++y) {
|
||
|
for (int x = x0; x < x0 + gwidth; ++x) {
|
||
|
|
||
|
int total_hits = 0;
|
||
|
|
||
|
for (int yy = 1; yy <= oversample_y; ++yy) {
|
||
|
for (int xx = 1; xx <= oversample_x; ++xx) {
|
||
|
u32 ncross = intersect_glyph(lines, nlines, x + norm_x * xx , y + norm_y * yy);
|
||
|
if (ncross) {
|
||
|
++total_hits;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (total_hits) {
|
||
|
u32 brightness = (256 - total_hits * 256 / (oversample_x * oversample_y)) * 0.99f;
|
||
|
pixels[y * width + x] = 0xFF000000 | brightness << 16 | brightness << 8 | brightness;
|
||
|
} else {
|
||
|
//pixels[y * width + x - 1] = 0xFFFF0000;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if DEBUG_SHOW_POINTS
|
||
|
_D_render_glyph_points(g, scale, pixels, width, height);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
|
||
|
{
|
||
|
int nlines = 0;
|
||
|
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 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.xmin) * scale;
|
||
|
f32 y1 = gp.y * scale;
|
||
|
|
||
|
f32 x2 = (nextgp.x - g.xmin) * scale;
|
||
|
f32 y2 = nextgp.y * 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.xmin) * scale;
|
||
|
f32 y3 = nextnextgp.y * scale;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if (nextgp.y != nextnextgp.y) {
|
||
|
if (dest->data) {
|
||
|
dest->data[nlines].a = (struct v2f) { x2, y2 };
|
||
|
dest->data[nlines].b = (struct v2f) { x3, y3 };
|
||
|
}
|
||
|
++nlines;
|
||
|
}
|
||
|
|
||
|
++p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dest->from[c + 1] = nlines;
|
||
|
|
||
|
points_from = g.end_pts_of_contours[c] + 1;
|
||
|
}
|
||
|
|
||
|
dest->ncontours = g.ncontours;
|
||
|
|
||
|
if (cnt) {
|
||
|
*cnt = nlines;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
if (argc != 2) {
|
||
|
fprintf(stderr, "Usage: %s filename.ttf\n", argv[0]);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
display = XOpenDisplay(0);
|
||
|
Window root_window = DefaultRootWindow(display);
|
||
|
|
||
|
int default_screen = DefaultScreen(display);
|
||
|
int screen_bit_depth = 24;
|
||
|
int width = 1280;
|
||
|
int height = 720;
|
||
|
|
||
|
XVisualInfo visinfo = { 0 };
|
||
|
XMatchVisualInfo(display, default_screen, screen_bit_depth, TrueColor, &visinfo);
|
||
|
|
||
|
XSetWindowAttributes window_attr;
|
||
|
window_attr.bit_gravity = StaticGravity;
|
||
|
window_attr.background_pixel = 0;
|
||
|
window_attr.colormap = XCreateColormap(display, root_window, visinfo.visual, AllocNone);
|
||
|
window_attr.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask;
|
||
|
|
||
|
unsigned long attribute_mask = CWBitGravity | CWBackPixel | CWColormap | CWEventMask;
|
||
|
|
||
|
window = XCreateWindow(display, root_window,
|
||
|
0, 0,
|
||
|
width, height, 0,
|
||
|
visinfo.depth, InputOutput,
|
||
|
visinfo.visual, attribute_mask, &window_attr);
|
||
|
|
||
|
XGrabPointer(display, window, False, ButtonPressMask | PointerMotionMask,
|
||
|
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
||
|
|
||
|
XSelectInput(display, window, KeyPress | KeyRelease | ButtonRelease | PointerMotionMask);
|
||
|
|
||
|
XStoreName(display, window, "ttf");
|
||
|
XMapWindow(display, window);
|
||
|
XFlush(display);
|
||
|
|
||
|
Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||
|
XSetWMProtocols(display, window, &WM_DELETE_WINDOW, 1);
|
||
|
|
||
|
int pixel_bits = 32;
|
||
|
int pixel_bytes = pixel_bits / 8;
|
||
|
int window_buffer_size = width * height * pixel_bytes;
|
||
|
void *hc_vram = malloc(window_buffer_size);
|
||
|
|
||
|
xwindow_buffer = XCreateImage(display, visinfo.visual, visinfo.depth, ZPixmap, 0, hc_vram, width, height,
|
||
|
pixel_bits, 0);
|
||
|
|
||
|
default_gc = DefaultGC(display, default_screen);
|
||
|
|
||
|
struct ttf_font font = parse_ttf_file(argv[1], "Inter");
|
||
|
printf("Loaded font\n");
|
||
|
|
||
|
//struct glyph g = get_outline(&font, 0x046C);
|
||
|
int codepoint = 0x0431;
|
||
|
struct glyph g = get_outline(&font, codepoint);
|
||
|
int nlines = 0;
|
||
|
|
||
|
u32 px_size = 120;
|
||
|
u32 *pixels = hc_vram;
|
||
|
int t = 0;
|
||
|
|
||
|
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
|
||
|
|
||
|
struct line_contour lines = { 0 };
|
||
|
outline_to_lines(g, scale, &lines, &nlines);
|
||
|
lines.data = malloc(nlines * sizeof(struct line));
|
||
|
outline_to_lines(g, scale, &lines, 0);
|
||
|
|
||
|
memset(pixels, 0xFFFFFFFF, width * height * 4);
|
||
|
render_grid(10, 10, pixels, width, height);
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
memset(pixels, 0xFFFFFFFF, width * height * 4);
|
||
|
render_grid(10, 10, pixels, width, height);
|
||
|
render_glyph(g, &lines, font, px_size, pixels, width, height);
|
||
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
|
||
|
|
||
|
#if 0
|
||
|
//printf("%d\n", px_size);
|
||
|
++px_size;
|
||
|
|
||
|
scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
|
||
|
free(lines.data);
|
||
|
lines.data = 0;
|
||
|
outline_to_lines(g, scale, &lines, &nlines);
|
||
|
lines.data = malloc(nlines * sizeof(struct line));
|
||
|
outline_to_lines(g, scale, &lines, 0);
|
||
|
|
||
|
if (px_size > 200) {
|
||
|
++codepoint;
|
||
|
g = get_outline(&font, codepoint);
|
||
|
printf("Loaded codepoint %#x\n", codepoint);
|
||
|
px_size = 20;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//sleep(1);
|
||
|
|
||
|
++t;
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|