diff --git a/dejavusansmono.data b/dejavusansmono.data index fa12698..aca0123 100644 Binary files a/dejavusansmono.data and b/dejavusansmono.data differ diff --git a/dejavusansmono_mono.data b/dejavusansmono_mono.data index 4d53cf8..6e74696 100644 Binary files a/dejavusansmono_mono.data and b/dejavusansmono_mono.data differ diff --git a/example/font_bitmap.cpp b/example/font_bitmap.cpp index 0065951..511dd63 100644 --- a/example/font_bitmap.cpp +++ b/example/font_bitmap.cpp @@ -189,7 +189,9 @@ inline void inflate_character(const uint8_t * src, const uint8_t c) } */ - twiddle::texture2<4>(&texture[offset / 4], temp, 8, 8, 0, 0); + twiddle::texture2<4>(&texture[offset / 4], temp, + 8, + 8 * 8); } void inflate_font(const uint8_t * src) diff --git a/example/font_outline.cpp b/example/font_outline.cpp index e43e1a5..8feebfe 100644 --- a/example/font_outline.cpp +++ b/example/font_outline.cpp @@ -125,14 +125,16 @@ void init_texture_memory(const struct opb_size& opb_size) ); } -void inflate_font(const uint32_t * src, const uint32_t size) +void inflate_font(const uint32_t * src, + const uint32_t stride, + const uint32_t curve_end_ix) { auto mem = reinterpret_cast(texture_memory64); auto texture = reinterpret_cast(mem->texture); - for (uint32_t i = 0; i < (size / 4); i++) { - texture[i] = src[i]; - } + twiddle::texture3<8, 8>(texture, reinterpret_cast(src), + stride, + curve_end_ix); } template @@ -150,7 +152,6 @@ void palette_data() | ((i >> 2) << 5) | ((i >> 3) << 0); } - holly.PALETTE_RAM[255] = 0xffff; } uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4]; @@ -167,6 +168,7 @@ void main() serial::integer(font->first_char_code); serial::integer(font->glyph_count); serial::integer(font->glyph_height); + serial::integer(font->texture_stride); serial::integer(font->texture_width); serial::integer(font->texture_height); serial::character('\n'); @@ -174,8 +176,9 @@ void main() serial::integer(((uint32_t)texture) - ((uint32_t)font)); */ - uint32_t texture_size = font->max_z_curve_ix + 1; - inflate_font(texture, texture_size); + inflate_font(texture, + font->texture_stride, + font->max_z_curve_ix); palette_data<256>(); // The address of `ta_parameter_buf` must be a multiple of 32 bytes. diff --git a/example/font_outline_punch_through.cpp b/example/font_outline_punch_through.cpp index 2a5b65c..cb119d4 100644 --- a/example/font_outline_punch_through.cpp +++ b/example/font_outline_punch_through.cpp @@ -130,18 +130,16 @@ constexpr inline uint32_t b(uint32_t v, uint32_t n) return ((v >> n) & 1) << (4 * n); } -void inflate_font(const uint32_t * src, const uint32_t size) +void inflate_font(const uint32_t * src, + const uint32_t stride, + const uint32_t curve_end_ix) { auto mem = reinterpret_cast(texture_memory64); auto texture = reinterpret_cast(mem->texture); - for (uint32_t i = 0; i < (size / 4); i++) { - uint32_t v = src[i]; - texture[(i * 4) + 0] = b(v, 7 ) | b(v, 6 ) | b(v, 5 ) | b(v, 4 ) | b(v, 3 ) | b(v, 2 ) | b(v, 1 ) | b(v, 0 ); - texture[(i * 4) + 1] = b(v, 15) | b(v, 14) | b(v, 13) | b(v, 12) | b(v, 11) | b(v, 10) | b(v, 9 ) | b(v, 8 ); - texture[(i * 4) + 2] = b(v, 23) | b(v, 22) | b(v, 21) | b(v, 20) | b(v, 19) | b(v, 18) | b(v, 17) | b(v, 16); - texture[(i * 4) + 3] = b(v, 31) | b(v, 30) | b(v, 29) | b(v, 28) | b(v, 27) | b(v, 26) | b(v, 25) | b(v, 24); - } + twiddle::texture3<4, 1>(texture, reinterpret_cast(src), + stride, + curve_end_ix); } template @@ -188,8 +186,9 @@ void main() serial::integer(((uint32_t)texture) - ((uint32_t)font)); */ - uint32_t texture_size = font->max_z_curve_ix + 1; - inflate_font(texture, texture_size); + inflate_font(texture, + font->texture_stride, + font->max_z_curve_ix); palette_data_mono(); // The address of `ta_parameter_buf` must be a multiple of 32 bytes. diff --git a/font/font.hpp b/font/font.hpp index ca8a05a..3f13133 100644 --- a/font/font.hpp +++ b/font/font.hpp @@ -32,9 +32,12 @@ struct font { uint32_t first_char_code; uint16_t glyph_count; uint16_t glyph_height; + uint16_t texture_stride; uint16_t texture_width; uint16_t texture_height; + uint16_t _pad; + uint32_t texture_size; uint32_t max_z_curve_ix; } __attribute__ ((packed)); -static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 4)); +static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 6)); diff --git a/tools/ttf_outline.cpp b/tools/ttf_outline.cpp index ceed772..2327b74 100644 --- a/tools/ttf_outline.cpp +++ b/tools/ttf_outline.cpp @@ -55,9 +55,11 @@ int32_t load_outline_char(const FT_Face face, const FT_Int32 load_flags, const FT_Render_Mode render_mode, + const uint32_t bits_per_pixel, const FT_ULong char_code, glyph * glyph, uint8_t * texture, + uint32_t texture_width, struct rect& rect) { FT_Error error; @@ -87,9 +89,16 @@ load_outline_char(const FT_Face face, assert(face->glyph->bitmap.width == rect.width); assert(face->glyph->bitmap.rows == rect.height); + assert(bits_per_pixel == 8 || bits_per_pixel == 4 || bits_per_pixel == 2 || bits_per_pixel == 1); + const uint32_t pixels_per_byte = 8 / bits_per_pixel; + const uint32_t texture_stride = texture_width / pixels_per_byte; + std::cerr << "pixels per byte: " << pixels_per_byte << '\n'; + std::cerr << "texture stride: " << texture_stride << '\n'; + for (uint32_t y = 0; y < rect.height; y++) { for (uint32_t x = 0; x < rect.width; x++) { - uint32_t texture_ix = (rect.y + y) * max_texture_dim + (rect.x + x); + const uint32_t texture_ix = (rect.y + y) * texture_stride + (rect.x + x) / pixels_per_byte; + const uint32_t texture_ix_mod = (rect.x + x) % pixels_per_byte; assert(texture_ix < max_texture_size); uint8_t level; @@ -108,12 +117,13 @@ load_outline_char(const FT_Face face, assert(face->glyph->bitmap.num_grays == 256); //std::cerr << "num_grays " << face->glyph->bitmap.num_grays << '\n'; level = face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch + x]; + level >>= (8 - bits_per_pixel); break; default: assert(false); break; } - texture[texture_ix] = level; + texture[texture_ix] |= level << (bits_per_pixel * texture_ix_mod); } } @@ -154,8 +164,6 @@ load_all_positions(const FT_Face face, const uint32_t num_glyphs = (end - start) + 1; struct rect rects[num_glyphs]; - uint8_t temp[max_texture_size]; - FT_Int32 load_flags; FT_Render_Mode render_mode; if (monochrome) { @@ -177,36 +185,23 @@ load_all_positions(const FT_Face face, // calculate a 2-dimensional packing for the rectangles auto window_curve_ix = pack_all(rects, num_glyphs); - // render all of the glyps to a temporary buffer; + const uint32_t bits_per_pixel = monochrome ? 1 : 8; + + // render all of the glyphs to the texture; for (uint32_t i = 0; i < num_glyphs; i++) { const uint32_t char_code = rects[i].char_code; int32_t err = load_outline_char(face, load_flags, render_mode, + bits_per_pixel, char_code, &glyphs[char_code - start], - temp, + reinterpret_cast(texture), + window_curve_ix.window.width, rects[i]); if (err < 0) assert(false); } - // twiddle the temporary buffer to become the final texture - if (monochrome) { - twiddle::texture2<1>(texture, temp, - window_curve_ix.window.width, - window_curve_ix.window.height, - max_texture_dim); - } else { - twiddle::texture2<8>(texture, temp, - window_curve_ix.window.width, - window_curve_ix.window.height, - max_texture_dim); - } - - if (monochrome) { - window_curve_ix.max_z_curve_ix = window_curve_ix.max_z_curve_ix / 8; - } - return window_curve_ix; } @@ -280,18 +275,32 @@ int main(int argc, char *argv[]) auto window_curve_ix = load_all_positions(face, monochrome, start, end, glyphs, texture); + uint32_t texture_stride; + uint32_t texture_size; + if (monochrome) { + texture_stride = window_curve_ix.window.width / 8; + texture_size = byteswap((window_curve_ix.max_z_curve_ix / 8) + 1); + } else { + texture_stride = window_curve_ix.window.width; + texture_size = byteswap((window_curve_ix.max_z_curve_ix / 1) + 1); + } + font font; font.first_char_code = byteswap(start); font.glyph_count = byteswap(num_glyphs); font.glyph_height = byteswap(face->size->metrics.height); + font.texture_stride = byteswap(texture_stride); font.texture_width = byteswap(window_curve_ix.window.width); font.texture_height = byteswap(window_curve_ix.window.height); + font.texture_size = byteswap(texture_size); font.max_z_curve_ix = byteswap(window_curve_ix.max_z_curve_ix); std::cerr << "start: 0x" << std::hex << start << '\n'; std::cerr << "end: 0x" << std::hex << end << '\n'; - std::cerr << "texture_width: " << std::dec << window_curve_ix.window.width << '\n'; + std::cerr << "texture_stride: " << std::dec << texture_stride << '\n'; + std::cerr << "texture_width: " << std::dec << window_curve_ix.window.width << '\n'; std::cerr << "texture_height: " << std::dec << window_curve_ix.window.height << '\n'; + std::cerr << "texture_size: " << std::dec << texture_size << '\n'; std::cerr << "max_z_curve_ix: " << std::dec << window_curve_ix.max_z_curve_ix << '\n'; FILE * out = fopen(argv[output_file_path], "w"); @@ -302,7 +311,7 @@ int main(int argc, char *argv[]) fwrite(reinterpret_cast(&font), (sizeof (font)), 1, out); fwrite(reinterpret_cast(&glyphs[0]), (sizeof (glyph)), num_glyphs, out); - fwrite(reinterpret_cast(&texture[0]), (sizeof (uint8_t)), window_curve_ix.max_z_curve_ix + 1, out); + fwrite(reinterpret_cast(&texture[0]), (sizeof (uint8_t)), texture_size, out); fclose(out); } diff --git a/twiddle.hpp b/twiddle.hpp index b46a22c..61a960e 100644 --- a/twiddle.hpp +++ b/twiddle.hpp @@ -137,28 +137,63 @@ void texture_4bpp(volatile T * dst, const T * src, const uint32_t width, const u } } -template +template void texture2(volatile T * dst, const U * src, - const uint32_t width, const uint32_t height, - const uint32_t stride) + const uint32_t src_stride, + const uint32_t curve_end_ix) { constexpr uint32_t t_bits = (sizeof (T)) * 8; - constexpr uint32_t bits_per_pixel = B; - static_assert(t_bits >= bits_per_pixel); - static_assert((t_bits / bits_per_pixel) * bits_per_pixel == t_bits); - constexpr uint32_t pixels_per_t = t_bits / bits_per_pixel; + static_assert(t_bits >= dst_bits_per_pixel); + static_assert((t_bits / dst_bits_per_pixel) * dst_bits_per_pixel == t_bits); + constexpr uint32_t pixels_per_t = t_bits / dst_bits_per_pixel; static_assert(pixels_per_t == 1 || pixels_per_t == 2 || pixels_per_t == 4 || pixels_per_t == 8 || pixels_per_t == 16 || pixels_per_t == 32); T dst_val = 0; - const uint32_t end_ix = from_xy(width - 1, height - 1); - for (uint32_t curve_ix = 0; curve_ix <= end_ix; curve_ix++) { + for (uint32_t curve_ix = 0; curve_ix <= curve_end_ix; curve_ix++) { auto [x, y] = from_ix(curve_ix); - const U src_val = src[y * stride + x]; + const U src_val = src[y * src_stride + x]; if constexpr (pixels_per_t == 1) { dst[curve_ix] = src_val; } else { const uint32_t curve_ix_mod = curve_ix & (pixels_per_t - 1); - dst_val |= src_val << (bits_per_pixel * curve_ix_mod); + dst_val |= src_val << (dst_bits_per_pixel * curve_ix_mod); + + if (curve_ix_mod == (pixels_per_t - 1)) { + dst[curve_ix / pixels_per_t] = dst_val; + dst_val = 0; + } + } + } +} + +template +void texture3(volatile T * dst, const U * src, + const uint32_t src_stride, + const uint32_t curve_end_ix) +{ + constexpr uint32_t t_bits = (sizeof (T)) * 8; + static_assert(t_bits >= dst_bits_per_pixel); + static_assert((t_bits / dst_bits_per_pixel) * dst_bits_per_pixel == t_bits); + constexpr uint32_t pixels_per_t = t_bits / dst_bits_per_pixel; + static_assert(pixels_per_t == 1 || pixels_per_t == 2 || pixels_per_t == 4 || pixels_per_t == 8 || pixels_per_t == 16 || pixels_per_t == 32); + + constexpr uint32_t u_bits = (sizeof (U)) * 8; + static_assert(u_bits >= src_bits_per_pixel); + static_assert((u_bits / src_bits_per_pixel) * src_bits_per_pixel == u_bits); + constexpr uint32_t pixels_per_u = u_bits / src_bits_per_pixel; + static_assert(pixels_per_u == 1 || pixels_per_u == 2 || pixels_per_u == 4 || pixels_per_u == 8 || pixels_per_u == 16 || pixels_per_u == 32); + + T dst_val = 0; + for (uint32_t curve_ix = 0; curve_ix <= curve_end_ix; curve_ix++) { + auto [x, y] = from_ix(curve_ix); + const uint32_t src_ix = y * src_stride + (x / pixels_per_u); + const uint32_t src_ix_mod = x & (pixels_per_u - 1); + const U src_val = (src[src_ix] >> (src_bits_per_pixel * src_ix_mod)) & ((1 << src_bits_per_pixel) - 1); + if constexpr (pixels_per_t == 1) { + dst[curve_ix] = src_val; + } else { + const uint32_t curve_ix_mod = curve_ix & (pixels_per_t - 1); + dst_val |= src_val << (dst_bits_per_pixel * curve_ix_mod); if (curve_ix_mod == (pixels_per_t - 1)) { dst[curve_ix / pixels_per_t] = dst_val;