From b484b5d4fe787b834468d4b5b252e4906dcb77f1 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sat, 23 Dec 2023 21:55:03 +0800 Subject: [PATCH] font_*: fully parameterize source/destination bit depth After implementing this, I realized I don't like the appearance of the monochrome font as much as the antialiased font. --- dejavusansmono.data | Bin 34605 -> 34613 bytes dejavusansmono_mono.data | Bin 5958 -> 5868 bytes example/font_bitmap.cpp | 4 +- example/font_outline.cpp | 17 ++++--- example/font_outline_punch_through.cpp | 19 ++++---- font/font.hpp | 5 ++- tools/ttf_outline.cpp | 59 ++++++++++++++----------- twiddle.hpp | 57 +++++++++++++++++++----- 8 files changed, 106 insertions(+), 55 deletions(-) diff --git a/dejavusansmono.data b/dejavusansmono.data index fa1269856ff28f00d8fbfd551bf06fa87c32f9c1..aca0123e0b5a0714f692fd12e8ed050a66355e2c 100644 GIT binary patch literal 34613 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 bFYm4k)qkCL|D$pb@hkDq{cOxRUi|+DVQ!VK literal 34605 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 aNlKdH*tETJE#11_u>XbM%GJM~_WuBO(X8?S diff --git a/dejavusansmono_mono.data b/dejavusansmono_mono.data index 4d53cf8b62fad6bdb3650b4dcff9ab5b21fc1f91..6e746966bc9d46597b0241974fa9735652cd2eaf 100644 GIT binary patch literal 5868 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 literal 5958 zcmZu#U8o~x8Gd6jO@9(+x2Nst-!@Zf5w*1OWFJ!!>12M z()yr@9G6?b7ZtQ?MDCL{IU;viS_jVp-aB!*V~H=S3gj-ACGUgsW!SxBqXSsO&| z$k8kK9*{Q<@g2E}-G{EiC-SR9{vEjr?c4HK#Cz1n+CkWi?HPF!2rTeh&|LY4+yuTp zF(3_?o{%YM*XJ}~N7`M;+hM*PsV&7uJ2ZGFJ`wdXZ`ZOm9)Z5Jfthnl>yc27W-K66o4@cqUWzL0+N!smjI`ULUQ zb_aJ>7P)NWp7|(fcLa;=R@=0Y561UUYaF+V0BCq z#ESyO>Sw9~td7fPAbX9?M?^erKK>0%Z?yQ?{J`g~d>68}T0XEZaCrrNeum*r!>odE_%>*!{Va6VXY-eGEu|18-Vz(Bw2sqp$ ze>=n%Ad;i-x!|Mhx8&zGmj#W!JPX}*RJ7d#po?+*!0wISMH=(=B}~dI`Az|=n~;b; z#3IDdhx~)6wIfTjj&`xe5@(Hl)fTpyftgiHNg^`Kv=p2Y8BJ>=sZBhQ_qOVRh)yc? zICiV^i8#hw(8P$-^W4!yE83D4)J6L~&e zR~a=izhxb|o5Lv_PSy2MN10!+))W%3V~le_%PEaSYTAxTUsfvv0(gea{xt1t8m{18 zSNyz}YFa`?%6a2BPyr|+*bReqorRu^Chia(d)kWk9S6SQo%Ex0qcrwcr8Lfbi8`m# z>PzuB3rm4Luf(x#f2!-^KA1}drD~TkQu9RD>geh%pk|4~eU<3sX>FZ-vIm;ZwH>9W zcfwNaH6Y(r8MGKXRu{TVT(=hZ42-)b(>Gz|oZw6&(j(cfiYqYyX=dSYKG4+HmbMy5 zUUwS5W*G)D@MPXgPOIF|H>vMVO?A&4w4H6wb$gzQN*&65^2mBky_!`PfCPTcl4*I;-QMcd@Mt!Y}WUvi8l4cEG zN_~lN=ZAuNTbZNIj8XqLb!{?+J>-qJx<8iGlWG4zwM@F8PIX&DlQ^PT#o_C7j{vtS>szQy_Jqy_(a1mp6>oq7hjM2q1Hapf0=x->mdv-{b*ya{`Oud8 zhX6WICl^=Js|=+w_dtkjY<%;tUDSzWy6Q{#r}DZAr6gs|9fVqjDw(f2yfB`Tt(i(> zx^n|$Mv&DV)+VtVXAhM8T^V$tVXbB*02XkL_Y{?@h+~lKYC2BOe;lH7k;8Of!;<>0 zifl=h@iAY#W?CWkqiOWf)&?3G`n|#Y>u@0+%|-8X*^1*VnuXOJ2NjGO4cQRL|HV~_ zXiq*OUu^RXnzaSy;H1b&d`V!wPU2cZbzIa_+<=aXD+K!_51^NogkHe4 zSd=wq$m=-h`Tfk-)slRmVU@j7EZstd%GBdCA^?_SOrBNDDaOVXd!PnIu39)HU`6~x zjI62%cSL!R>?9$W!J??de8nPr3rsQNXo5?7AG@*VmKFWQY(xJ&q}zI7m2nNmFAV20 zL@(G`W@~yEJ8XGX*h5_Us7CMh#xH2yjY={$I@Z5DcL#gi#Fc8_aIU++Ag}IG;t+F- zR}!Q;L`^sjzr>GUlt_C9gy9d2+U^E^v^37*aigkjZSh&Bm>WIEwR6>MZju*W)H3E? z$26VN++#g>R+iX#(lu7+3CK1vC26k)Kg$a|w(NYF&{DpvKS`3bB{>fSxdu}Ef`gtD zLBj+S>{cn@)V9-t(hX(*(YG!@KtGD!3p<+NZHa6fQOv1}g*?R41qaQokM?!vm&_&n zN6mTUKm|f4*Pv(Vn$=uAq0NG>hWp@9smS&qS&3_`JDGnL7-KDRO?qs!%KB4vA%yI3 z=HS{yJ>?D8WPDhy-K>p03+KZ&{ch&yV@D3-!v8^%0nc;R#@gN-a@c)k4qzfNM6+c2KSn@_Z)mQ*b~6d5Qrd>LeG7(fEGQ5Me93KkVz+G#vP30YT2Y9=xLR zJ?uW%>8(6_o-+rF^2&L%XX`A=V&hlQeRGLJmlgFpw=Ue@&<$JIS4OxR8MAwlJTY17 zV;)U8-!am=`{8@0>gaY2+A+4Dcj}GOXbbI@9cWMAZ zm(SC4kV&x1xvC#34&Z^VGD58JtPy28ui|}J^eQk0W|*ABYnEhwcaC`!qsKu%kN9J+ z0&~o*T9+GT~ zlAzqn{iEN=kzIpqN9As*)G?@sS_Jv_cKXRm3s(ABVLd`EVE)6; z;8~fSZmcbODy){|gu+smhCJt>yGF9RttLecaW0ova54~OO*MxlcoRI9o!7Tn#I;e9 zkj`&n{`(fL8ge#b&Eq<41rGL>Dbk4}f7M5F)&zm|WzZB2L>DQm0^_5@n0oODvxwM=Zq&9YB(=MP_Ov?u!dw~9J=~;>;oLYgPBU4F0O+} z(O)y3A9yn1vgZf<*su?^wSqOpO&@z%8T+1fh3T+MC;5Em9JDLiPs5;`=RB_goIgEy z5)Y@ZqXri9V)tE)8#RUh*sW$0gUT!X-*}(<)f~S=+GXIaCEz~9FNf*^&)yrqwtayj zgDkojCsM2)p9JSB_6~caXgur-@PU}-^x{e(iSPoiP`~Uk*Ts2doNCsXV)mHiKu4I2 z#=LVu-{x+>Z<55cSQ%p0`8dnwXC))pyOUMCl}*vjO;ilh$$bP1x|(pA&5WL2TqEdS z1-7(}-%cpGu(TW4e?d~l`lPKI}) zwWB!s_Du~D88gMP)y}GQ)8tth4qGgc1SeU;>{;0|ZW;ZJ1JWAzUN`9>$Gb)SF3w%T z9esksD*O+o=wJHH{z}_niC60$utiP($fO_ZFL2Vto@?hW`$BhIcN4UtPl#m&zln$_ zJA`}KXcA#kV7ENmz)v*QaW+kenGe4jCC-qA9TGXz_OB|AWaG0{{R3 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;