diff options
Diffstat (limited to 'v_windows/v/vlib/x/ttf/render_bmp.v')
-rw-r--r-- | v_windows/v/vlib/x/ttf/render_bmp.v | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/v_windows/v/vlib/x/ttf/render_bmp.v b/v_windows/v/vlib/x/ttf/render_bmp.v new file mode 100644 index 0000000..c0cf6dc --- /dev/null +++ b/v_windows/v/vlib/x/ttf/render_bmp.v @@ -0,0 +1,825 @@ +module ttf + +/********************************************************************** +* +* BMP render module utility functions +* +* Copyright (c) 2021 Dario Deledda. All rights reserved. +* Use of this source code is governed by an MIT license +* that can be found in the LICENSE file. +* +* Note: +* +* TODO: +* - manage text directions R to L +**********************************************************************/ +import encoding.utf8 +import math +import math.mathutil as mu + +pub struct BitMap { +pub mut: + tf &TTF_File + buf &byte = 0 // pointer to the memory buffer + buf_size int // allocated buf size in bytes + width int = 1 // width of the buffer + height int = 1 // height of the buffer + bp int = 4 // byte per pixel of the buffer + bg_color u32 = 0xFFFFFF_00 // background RGBA format + color u32 = 0x000000_FF // RGBA format + scale f32 = 1.0 // internal usage!! + scale_x f32 = 1.0 // X scale of the single glyph + scale_y f32 = 1.0 // Y scale of the single glyph + angle f32 = 0.0 // angle of rotation of the bitmap + // spaces + space_cw f32 = 1.0 // width of the space glyph internal usage!! + space_mult f32 = f32(0.0) // 1.0/16.0 // space between letter, is a multiplier for a standrd space ax + // used only by internal text rendering!! + tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix + ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix + style Style = .filled // default syle + align Text_align = .left // default text align + justify bool // justify text flag, default deactivated + justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text + filler [][]int // filler buffer for the renderer + // flag to force font embedded metrics + use_font_metrics bool +} + +/****************************************************************************** +* +* Utility +* +******************************************************************************/ +// clear clear the bitmap with 0 bytes +pub fn (mut bmp BitMap) clear() { + mut sz := bmp.width * bmp.height * bmp.bp + unsafe { + C.memset(bmp.buf, 0x00, sz) + } +} + +// transform matrix applied to the text +fn (bmp &BitMap) trf_txt(p &Point) (int, int) { + return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), int( + p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7]) +} + +// transform matrix applied to the char +fn (bmp &BitMap) trf_ch(p &Point) (int, int) { + return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), int( + p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7]) +} + +// set draw postion in the buffer +pub fn (mut bmp BitMap) set_pos(x f32, y f32) { + bmp.tr_matrix[6] = x + bmp.tr_matrix[7] = y +} + +// set the rotation angle in radiants +pub fn (mut bmp BitMap) set_rotation(a f32) { + bmp.tr_matrix[0] = f32(math.cos(a)) // 1 + bmp.tr_matrix[1] = f32(-math.sin(a)) // 0 + bmp.tr_matrix[3] = f32(math.sin(a)) // 0 + bmp.tr_matrix[4] = f32(math.cos(a)) // 1 +} + +/****************************************************************************** +* +* Filler functions +* +******************************************************************************/ +pub fn (mut bmp BitMap) init_filler() { + h := bmp.height - bmp.filler.len + if h < 1 { + return + } + for _ in 0 .. h { + bmp.filler << []int{len: 4} + } + // dprintln("Init filler: ${bmp.filler.len} rows") +} + +pub fn (mut bmp BitMap) clear_filler() { + for i in 0 .. bmp.height { + bmp.filler[i].clear() + } +} + +pub fn (mut bmp BitMap) exec_filler() { + for y in 0 .. bmp.height { + if bmp.filler[y].len > 0 { + bmp.filler[y].sort() + if bmp.filler[y].len & 1 != 0 { + // dprintln("even line!! $y => ${bmp.filler[y]}") + continue + } + mut index := 0 + for index < bmp.filler[y].len { + startx := bmp.filler[y][index] + 1 + endx := bmp.filler[y][index + 1] + if startx >= endx { + index += 2 + continue + } + for x in startx .. endx { + bmp.plot(x, y, bmp.color) + } + index += 2 + } + } + } +} + +pub fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) { + mut x0 := f32(in_x0) + mut x1 := f32(in_x1) + mut y0 := f32(in_y0) + mut y1 := f32(in_y1) + mut tmp := f32(0) + + // check bounds + if (in_x0 < 0 && in_x1 < 0) || (in_x0 > bmp.width && in_x1 > bmp.width) { + return + } + + if y1 < y0 { + tmp = x0 + x0 = x1 + x1 = tmp + + tmp = y0 + y0 = y1 + y1 = tmp + } + + mut dx := x1 - x0 + mut dy := y1 - y0 + + if dy == 0 { + if in_y0 >= 0 && in_y0 < bmp.filler.len { + if in_x0 <= in_x1 { + bmp.filler[in_y0] << in_x0 + bmp.filler[in_y0] << in_x1 + } else { + bmp.filler[in_y0] << in_x1 + bmp.filler[in_y0] << in_x0 + } + } + return + } + mut n := dx / dy + for y in 0 .. int(dy + 0.5) { + yd := int(y + y0) + x := n * y + x0 + if x > bmp.width || yd >= bmp.filler.len { + break + } + if yd >= 0 && yd < bmp.filler.len { + bmp.filler[yd] << int(x + 0.5) + // bmp.plot(int(x+0.5), yd, bmp.color) + } + } +} + +/****************************************************************************** +* +* Draw functions +* +******************************************************************************/ +[inline] +pub fn (mut bmp BitMap) plot(x int, y int, c u32) bool { + if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height { + return false + } + mut index := (x + y * bmp.width) * bmp.bp + unsafe { + // bmp.buf[index]=0xFF + bmp.buf[index] = byte(c & 0xFF) // write only the alpha + } + /* + for count in 0..(bmp.bp) { + unsafe{ + bmp.buf[index + count] = byte((c >> (bmp.bp - count - 1) * 8) & 0x0000_00FF) + } + } + */ + return true +} + +/****************************************************************************** +* +* smooth draw functions +* +******************************************************************************/ +// aline draw an aliased line on the bitmap +pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) { + // mut c1 := c + mut x0 := f32(in_x0) + mut x1 := f32(in_x1) + mut y0 := f32(in_y0) + mut y1 := f32(in_y1) + mut tmp := f32(0) + + mut dx := x1 - x0 + mut dy := y1 - y0 + + dist := f32(0.4) + + if mu.abs(dx) > mu.abs(dy) { + if x1 < x0 { + tmp = x0 + x0 = x1 + x1 = tmp + + tmp = y0 + y0 = y1 + y1 = tmp + } + dx = x1 - x0 + dy = y1 - y0 + + x0 += 0.5 + y0 += 0.5 + + m := dy / dx + mut x := x0 + for x <= x1 + 0.5 { + y := m * (x - x0) + y0 + e := 1 - mu.abs(y - 0.5 - int(y)) + bmp.plot(int(x), int(y), color_multiply_alpha(c, e * 0.75)) + + ys1 := y + dist + if int(ys1) != int(y) { + v1 := mu.abs(ys1 - y) / dist * (1 - e) + bmp.plot(int(x), int(ys1), color_multiply_alpha(c, v1)) + } + + ys2 := y - dist + if int(ys2) != int(y) { + v2 := mu.abs(y - ys2) / dist * (1 - e) + bmp.plot(int(x), int(ys2), color_multiply_alpha(c, v2)) + } + + x += 1.0 + } + } else { + if y1 < y0 { + tmp = x0 + x0 = x1 + x1 = tmp + + tmp = y0 + y0 = y1 + y1 = tmp + } + dx = x1 - x0 + dy = y1 - y0 + + x0 += 0.5 + y0 += 0.5 + + n := dx / dy + mut y := y0 + for y <= y1 + 0.5 { + x := n * (y - y0) + x0 + e := f32(1 - mu.abs(x - 0.5 - int(x))) + bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e * 0.75))) + + xs1 := x + dist + if int(xs1) != int(x) { + v1 := mu.abs(xs1 - x) / dist * (1 - e) + bmp.plot(int(xs1), int(y), color_multiply_alpha(c, f32(v1))) + } + + xs2 := x - dist + if int(xs2) != int(x) { + v2 := mu.abs(x - xs1) / dist * (1 - e) + bmp.plot(int(xs2), int(y), color_multiply_alpha(c, f32(v2))) + } + y += 1.0 + } + } +} + +/****************************************************************************** +* +* draw functions +* +******************************************************************************/ +pub fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) { + // outline with aliased borders + if bmp.style == .outline_aliased { + bmp.aline(in_x0, in_y0, in_x1, in_y1, c) + return + } + // filled with aliased borders + else if bmp.style == .filled { + bmp.aline(in_x0, in_y0, in_x1, in_y1, c) + bmp.fline(in_x0, in_y0, in_x1, in_y1, c) + return + } + // only the filler is drawn + else if bmp.style == .raw { + bmp.fline(in_x0, in_y0, in_x1, in_y1, c) + return + } + // if we are here we are drawing an outlined border + + x0 := int(in_x0) + x1 := int(in_x1) + y0 := int(in_y0) + y1 := int(in_y1) + // dprintln("line[$x0,$y0,$x1,$y1]") + + mut x := x0 + mut y := y0 + + dx := mu.abs(x1 - x0) + sx := if x0 < x1 { 1 } else { -1 } + dy := -mu.abs(y1 - y0) + sy := if y0 < y1 { 1 } else { -1 } + + // verical line + if dx == 0 { + if y0 < y1 { + for yt in y0 .. y1 + 1 { + bmp.plot(x0, yt, c) + } + return + } + for yt in y1 .. y0 + 1 { + bmp.plot(x0, yt, c) + } + // horizontal line + return + } else if dy == 0 { + if x0 < x1 { + for xt in x0 .. x1 + 1 { + bmp.plot(xt, y0, c) + } + return + } + for xt in x1 .. x0 + 1 { + bmp.plot(xt, y0, c) + } + return + } + + mut err := dx + dy // error value e_xy + for { + // bmp.plot(x, y, u32(0xFF00)) + bmp.plot(x, y, c) + + // dprintln("$x $y [$x0,$y0,$x1,$y1]") + if x == x1 && y == y1 { + break + } + e2 := 2 * err + if e2 >= dy { // e_xy+e_x > 0 + err += dy + x += sx + } + if e2 <= dx { // e_xy+e_y < 0 + err += dx + y += sy + } + } +} + +pub fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) { + bmp.line(in_x0, in_y0, in_x1, in_y0, c) + bmp.line(in_x1, in_y0, in_x1, in_y1, c) + bmp.line(in_x0, in_y1, in_x1, in_y1, c) + bmp.line(in_x0, in_y0, in_x0, in_y1, c) +} + +pub fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32) { + /* + x0 := int(in_x0 * bmp.scale) + x1 := int(in_x1 * bmp.scale) + y0 := int(in_y0 * bmp.scale) + y1 := int(in_y1 * bmp.scale) + cx := int(in_cx * bmp.scale) + cy := int(in_cy * bmp.scale) + */ + x0 := int(in_x0) + x1 := int(in_x1) + y0 := int(in_y0) + y1 := int(in_y1) + cx := int(in_cx) + cy := int(in_cy) + + mut division := f64(1.0) + dx := mu.abs(x0 - x1) + dy := mu.abs(y0 - y1) + + // if few pixel draw a simple line + // if dx == 0 && dy == 0 { + if dx <= 2 || dy <= 2 { + // bmp.plot(x0, y0, c) + bmp.line(x0, y0, x1, y1, c) + return + } + + division = 1.0 / (f64(if dx > dy { dx } else { dy })) + + // division = 0.1 // 10 division + // division = 0.25 // 4 division + + // dprintln("div: $division") + + /* + ----- Bezier quadratic form ----- + t = 0.5; // given example value, half length of the curve + x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x; + y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y; + --------------------------------- + */ + + mut x_old := x0 + mut y_old := y0 + mut t := 0.0 + + for t <= (1.0 + division / 2.0) { + s := 1.0 - t + x := s * s * x0 + 2.0 * s * t * cx + t * t * x1 + y := s * s * y0 + 2.0 * s * t * cy + t * t * y1 + xi := int(x + 0.5) + yi := int(y + 0.5) + // bmp.plot(xi, yi, c) + bmp.line(x_old, y_old, xi, yi, c) + x_old = xi + y_old = yi + t += division + } +} + +/****************************************************************************** +* +* TTF Query functions +* +******************************************************************************/ +pub fn (mut bmp BitMap) get_chars_bbox(in_string string) []int { + mut res := []int{} + mut w := 0 + + mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) + div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) + space_cw = int(space_cw * bmp.scale) + + bmp.tf.reset_kern() + + mut i := 0 + for i < in_string.len { + mut char := u16(in_string[i]) + + // draw the space + if int(char) == 32 { + w += int(space_cw * bmp.space_cw) + i++ + continue + } + // manage unicode chars like latin greek etc + c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 + if c_len > 1 { + tmp_char := utf8.get_uchar(in_string, i) + // dprintln("tmp_char: ${tmp_char.hex()}") + char = u16(tmp_char) + } + + c_index := bmp.tf.map_code(int(char)) + // Glyph not found + if c_index == 0 { + w += int(space_cw * bmp.space_cw) + i += c_len + continue + } + + ax, ay := bmp.tf.next_kern(c_index) + // dprintln("char_index: $c_index ax: $ax ay: $ay") + + // cw, lsb := bmp.tf.get_horizontal_metrics(u16(char)) + // dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb") + + //----- Calc Glyph transformations ----- + mut x0 := w + int(ax * bmp.scale) + mut y0 := 0 + int(ay * bmp.scale) + + p := Point{x0, y0, false} + x1, y1 := bmp.trf_txt(p) + // init ch_matrix + bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x + bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x + bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[6] = int(x1) + bmp.ch_matrix[7] = int(y1) + + // x_min, x_max, y_min, y_max := bmp.tf.read_glyph_dim(c_index) + x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index) + //----------------- + + width := int((mu.abs(x_max + x_min) + ax) * bmp.scale) + // width := int((cw+ax) * bmp.scale) + w += width + div_space_cw + h := int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) + res << w + res << h + + i += c_len + } + return res +} + +pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) { + mut w := 0 + + mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) + div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) + space_cw = int(space_cw * bmp.scale) + + bmp.tf.reset_kern() + + mut i := 0 + for i < in_string.len { + mut char := u16(in_string[i]) + + // draw the space + if int(char) == 32 { + w += int(space_cw * bmp.space_cw) + i++ + continue + } + // manage unicode chars like latin greek etc + c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 + if c_len > 1 { + tmp_char := utf8.get_uchar(in_string, i) + // dprintln("tmp_char: ${tmp_char.hex()}") + char = u16(tmp_char) + } + + c_index := bmp.tf.map_code(int(char)) + // Glyph not found + if c_index == 0 { + w += int(space_cw * bmp.space_cw) + i += c_len + continue + } + ax, ay := bmp.tf.next_kern(c_index) + // dprintln("char_index: $c_index ax: $ax ay: $ay") + + // cw, lsb := bmp.tf.get_horizontal_metrics(u16(char)) + // dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb") + + //----- Calc Glyph transformations ----- + mut x0 := w + int(ax * bmp.scale) + mut y0 := 0 + int(ay * bmp.scale) + + p := Point{x0, y0, false} + x1, y1 := bmp.trf_txt(p) + // init ch_matrix + bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x + bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x + bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[6] = int(x1) + bmp.ch_matrix[7] = int(y1) + + x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index) + // x_min := 1 + // x_max := 2 + //----------------- + + width := int((mu.abs(x_max + x_min) + ax) * bmp.scale) + // width := int((cw+ax) * bmp.scale) + w += width + div_space_cw + + i += c_len + } + + // dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}") + // buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) ) + return w, int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) +} + +/****************************************************************************** +* +* TTF draw glyph +* +******************************************************************************/ +fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) { + mut p := Point{in_x, 0, false} + x1, y1 := bmp.trf_txt(p) + // init ch_matrix + bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x + bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x + bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[6] = int(x1) + bmp.ch_matrix[7] = int(y1) + x, y := bmp.trf_ch(p) + + y_h := mu.abs(bmp.tf.y_max - bmp.tf.y_min) * bmp.scale * 0.5 + + bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color) + bmp.line(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color) + bmp.line(int(x - in_w), int(y), int(x), int(y - y_h), bmp.color) +} + +pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) { + mut w := 0 + + mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) + div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) + space_cw = int(space_cw * bmp.scale) + + bmp.tf.reset_kern() + + mut i := 0 + for i < in_string.len { + mut char := u16(in_string[i]) + + // draw the space + if int(char) == 32 { + w += int(space_cw * bmp.space_cw) + i++ + continue + } + // manage unicode chars like latin greek etc + c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 + if c_len > 1 { + tmp_char := utf8.get_uchar(in_string, i) + // dprintln("tmp_char: ${tmp_char.hex()}") + char = u16(tmp_char) + } + + c_index := bmp.tf.map_code(int(char)) + // Glyph not found + if c_index == 0 { + bmp.draw_notdef_glyph(w, int(space_cw * bmp.space_cw)) + w += int(space_cw * bmp.space_cw) + i += c_len + continue + } + + ax, ay := bmp.tf.next_kern(c_index) + // dprintln("char_index: $c_index ax: $ax ay: $ay") + + cw, _ := bmp.tf.get_horizontal_metrics(u16(char)) + // cw, lsb := bmp.tf.get_horizontal_metrics(u16(char)) + // dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb") + + //----- Draw_Glyph transformations ----- + mut x0 := w + int(ax * bmp.scale) + mut y0 := 0 + int(ay * bmp.scale) + + p := Point{x0, y0, false} + x1, y1 := bmp.trf_txt(p) + // init ch_matrix + bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x + bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x + bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y + bmp.ch_matrix[6] = int(x1) + bmp.ch_matrix[7] = int(y1) + + x_min, x_max := bmp.draw_glyph(c_index) + // x_min := 1 + // x_max := 2 + //----------------- + + mut width := int((mu.abs(x_max + x_min) + ax) * bmp.scale) + if bmp.use_font_metrics { + width = int((cw + ax) * bmp.scale) + } + w += width + div_space_cw + i += c_len + } + + // dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}") + // buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) ) + return w, int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) +} + +pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) { + glyph := bmp.tf.read_glyph(index) + + if !glyph.valid_glyph { + return 0, 0 + } + + if bmp.style == .filled || bmp.style == .raw { + bmp.clear_filler() + } + + mut s := 0 // status + mut c := 0 // contours count + mut contour_start := 0 + mut x0 := 0 + mut y0 := 0 + color := bmp.color // u32(0xFFFF_FF00) // RGBA white + // color1 := u32(0xFF00_0000) // RGBA red + // color2 := u32(0x00FF_0000) // RGBA green + + mut sp_x := 0 + mut sp_y := 0 + mut point := Point{} + + for count, point_raw in glyph.points { + // dprintln("count: $count, state: $s pl:$glyph.points.len") + point.x = point_raw.x + point.y = point_raw.y + + point.x, point.y = bmp.trf_ch(point) + point.on_curve = point_raw.on_curve + + if s == 0 { + x0 = point.x + y0 = point.y + sp_x = x0 + sp_y = y0 + s = 1 // next state + continue + } else if s == 1 { + if point.on_curve { + bmp.line(x0, y0, point.x, point.y, color) + // bmp.aline(x0, y0, point.x, point.y, u32(0xFFFF0000)) + x0 = point.x + y0 = point.y + } else { + s = 2 + } + } else { + // dprintln("s==2") + mut prev := glyph.points[count - 1] + prev.x, prev.y = bmp.trf_ch(prev) + if point.on_curve { + // dprintln("HERE1") + // ctx.quadraticCurveTo(prev.x + x, prev.y + y,point.x + x, point.y + y); + // bmp.line(x0, y0, point.x + in_x, point.y + in_y, color1) + // bmp.quadratic(x0, y0, point.x + in_x, point.y + in_y, prev.x + in_x, prev.y + in_y, u32(0xa0a00000)) + bmp.quadratic(x0, y0, point.x, point.y, prev.x, prev.y, color) + x0 = point.x + y0 = point.y + s = 1 + } else { + // dprintln("HERE2") + // ctx.quadraticCurveTo(prev.x + x, prev.y + y, + // (prev.x + point.x) / 2 + x, + // (prev.y + point.y) / 2 + y); + + // bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2) + // bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2) + bmp.quadratic(x0, y0, (prev.x + point.x) / 2, (prev.y + point.y) / 2, + prev.x, prev.y, color) + x0 = (prev.x + point.x) / 2 + y0 = (prev.y + point.y) / 2 + } + } + + if count == glyph.contour_ends[c] { + // dprintln("count == glyph.contour_ends[count]") + if s == 2 { // final point was off-curve. connect to start + + mut start_point := glyph.points[contour_start] + start_point.x, start_point.y = bmp.trf_ch(start_point) + if point.on_curve { + // ctx.quadraticCurveTo(prev.x + x, prev.y + y, + // point.x + x, point.y + y); + // bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000)) + + // start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00)) + bmp.quadratic(x0, y0, start_point.x, start_point.y, start_point.x, + start_point.y, color) + } else { + // ctx.quadraticCurveTo(prev.x + x, prev.y + y, + // (prev.x + point.x) / 2 + x, + // (prev.y + point.y) / 2 + y); + + // bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000) + // u32(0xFF000000)) + bmp.quadratic(x0, y0, start_point.x, start_point.y, (point.x + start_point.x) / 2, + (point.y + start_point.y) / 2, color) + } + } else { + // last point not in a curve + // bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000)) + bmp.line(point.x, point.y, sp_x, sp_y, color) + } + contour_start = count + 1 + s = 0 + c++ + } + } + + if bmp.style == .filled || bmp.style == .raw { + bmp.exec_filler() + } + x_min := glyph.x_min + x_max := glyph.x_max + return x_min, x_max + + // return glyph.x_min, glyph.x_max +} |