Browse Source

Sorted intersections!

master
A.Olokhtonov 4 years ago
parent
commit
5ef139d533
  1. 222
      main.c
  2. 2
      ttf2.c

222
main.c

@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
#include <string.h>
#include <stdbool.h>
#include <wchar.h>
#include <assert.h>
#include <unistd.h>
@ -24,8 +26,6 @@ @@ -24,8 +26,6 @@
#define F32EPS 1e-5f
#define MAX_CONTOURS 16
#define PER_PIXEL 0
#define PER_ROW 0
#define DEBUG_SHOW_POINTS 0
/*
@ -82,6 +82,17 @@ struct line_contour { @@ -82,6 +82,17 @@ struct line_contour {
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;
@ -139,6 +150,8 @@ struct head_table { @@ -139,6 +150,8 @@ struct head_table {
struct hhea_table {
int ascent;
int descent;
int line_gap;
int max_advance;
};
struct glyph_point {
@ -218,28 +231,26 @@ round_f32(f32 v) @@ -218,28 +231,26 @@ round_f32(f32 v)
}
static int
scanline_intersects_line(f32 x, f32 y, struct v2f p0, struct v2f p1, f32 lasty)
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 (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);
*vx = x1;
return(result);
}
}
if (0 < t1 && t1 < 1.0f) {
f32 x1 = p0.x + (p1.x - p0.x) * t1;
if (x1 > x) {
*vx = x1;
int result = (goes_up ? 1 : -1);
return(result);
}
}
return(0);
}
@ -341,9 +352,9 @@ render_grid(int x_step, int y_step, u32 *pixels, int width, int height) @@ -341,9 +352,9 @@ render_grid(int x_step, int y_step, u32 *pixels, int width, int height)
}
static int
intersect_glyph(struct line_contour *lines, f32 x, f32 y)
intersect_glyph(struct line_contour *lines, f32 y, struct intersection *intersections)
{
int result = 0;
int nints = 0;
for (int c = 0; c < lines->ncontours; ++c) {
int from = lines->from[c];
@ -352,12 +363,18 @@ intersect_glyph(struct line_contour *lines, f32 x, f32 y) @@ -352,12 +363,18 @@ intersect_glyph(struct line_contour *lines, f32 x, f32 y)
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;
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(result);
return(nints);
}
static void
@ -396,83 +413,64 @@ _D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int he @@ -396,83 +413,64 @@ _D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int he
}
static void
render_glyph(struct glyph g, struct line_contour *lines,
struct ttf_font font, int px_size, u32 *pixels, int width, int height)
sort_intersections(struct intersection *intersections, int size)
{
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent));
//int npoints = g.end_pts_of_contours[g.ncontours - 1] + 1;
bool swapped = true;
if (g.advance < 0) {
g.advance *= -1;
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;
}
}
}
}
int x0 = 0; // g.xmin * scale;
int gwidth = (g.xmax - g.xmin) * scale;
int gheight = (g.ymax - g.ymin) * scale + 1;
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);
static void
render_glyph(struct glyph g, struct line_contour *lines,
f32 scale, u32 *pixels, int width, int height, int at_x, int at_y)
{
int gwidth = round_f32((g.xmax - g.xmin) * scale) + 1;
int gheight = round_f32((g.ymax - g.ymin) * scale) + 1;
//if (ncross) {
//continue;
//}
struct intersection *intersections = malloc(lines->from[lines->ncontours] * sizeof(struct intersection));
for (int x = x0; x < x0 + gwidth; ++x) {
u32 ncross = intersect_glyph(lines, x + 0.5f, y + 0.5f);
for (int y = 0; y < gheight && (at_y + y < height); ++y) {
u32 ncross = intersect_glyph(lines, y, intersections);
if (ncross) {
pixels[y * width + x] = 0x00;
} else {
pixels[y * width + x] = 0xFFFF0000;
}
sort_intersections(intersections, ncross);
#if PER_PIXEL
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
#endif
}
int state = 0;
#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 i = 0; i < ncross - 1; ++i) {
struct intersection inter = intersections[i];
struct intersection next_inter = intersections[i + 1];
for (int y = 0; y < gheight; ++y) {
for (int x = x0; x < x0 + gwidth; ++x) {
state += inter.dir;
int total_hits = 0;
if (state != 0) {
f32 x0 = inter.x;
f32 x1 = next_inter.x;
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;
}
for (int x = x0; x < x1; ++x) {
pixels[(y + at_y) * width + (at_x + x)] = 0x00;
}
}
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
}
free(intersections);
}
static void
@ -493,11 +491,11 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) @@ -493,11 +491,11 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
continue;
}
f32 x1 = (gp.x - g.xmin) * scale;
f32 y1 = gp.y * scale;
f32 x1 = round_f32((gp.x - g.xmin) * scale);
f32 y1 = round_f32(gp.y * scale);
f32 x2 = (nextgp.x - g.xmin) * scale;
f32 y2 = nextgp.y * scale;
f32 x2 = round_f32((nextgp.x - g.xmin) * scale);
f32 y2 = round_f32(nextgp.y * scale);
if (nextgp.on_curve) {
if (gp.y != nextgp.y) {
@ -511,8 +509,8 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) @@ -511,8 +509,8 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
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;
f32 x3 = round_f32((nextnextgp.x - g.xmin) * scale);
f32 y3 = round_f32(nextnextgp.y * scale);
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */
f32 t_step = 1.0f / curve_segments;
@ -567,6 +565,40 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) @@ -567,6 +565,40 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
}
}
static void
render_utf_string(struct ttf_font font, int px_size, u32 *pixels, u32 width, u32 height, 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);
struct line_contour lines = { 0 };
int nlines = 0;
outline_to_lines(g, scale, &lines, &nlines);
lines.data = malloc(nlines * sizeof(struct line));
outline_to_lines(g, scale, &lines, 0);
int baseline_correction = round_f32(scale * g.ymax);
render_glyph(g, &lines, scale, pixels, width, height, offset_x + g.lsb * scale, offset_y - baseline_correction);
offset_x += 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)
{
@ -625,50 +657,16 @@ main(int argc, char **argv) @@ -625,50 +657,16 @@ main(int argc, char **argv)
struct ttf_font font = parse_ttf_file(argv[1], "Inter");
printf("Loaded font\n");
//struct glyph g = get_outline(&font, 0x046C);
int codepoint = 0x0020;
struct glyph g = get_outline(&font, codepoint);
int nlines = 0;
u32 px_size = 20;
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 1
//printf("%d\n", px_size);
++px_size;
render_utf_string(font, 32, pixels, width, height, L"Привет, батя! Как поживаешь? Hello, Batya. Wazzaaap", 100, 100);
render_utf_string(font, 32, pixels, width, height, L"QQQQqqqqq", 100, 200);
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
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
//sleep(1);

2
ttf2.c

@ -631,6 +631,8 @@ read_hhea(struct font_directory font_dir, struct ttf_font *font) @@ -631,6 +631,8 @@ read_hhea(struct font_directory font_dir, struct ttf_font *font)
{
font->hhea.ascent = be16s(font->file.data + font_dir.hhea_offset + 4);
font->hhea.descent = be16s(font->file.data + font_dir.hhea_offset + 6);
font->hhea.line_gap = be16s(font->file.data + font_dir.hhea_offset + 10);
font->hhea.max_advance = be16(font->file.data + font_dir.hhea_offset + 14);
}
static void

Loading…
Cancel
Save