💾 Archived View for gmi.noulin.net › gitRepositories › heartbeat › file › shpPackages › termbox › tf… captured on 2024-06-20 at 11:56:07. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
tfont.c (12806B)
1 #! /usr/bin/env sheepy 2 /* or direct path to sheepy: #! /usr/local/bin/sheepy */ 3 4 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ 5 #include "libsheepyObject.h" 6 #include "termbox.h" 7 8 int argc; char **argv; 9 10 /* enable/disable logging */ 11 /* #undef pLog */ 12 /* #define pLog(...) */ 13 14 #define FONT_DIR "~/.termfont/" 15 16 typ struct { 17 u32 width; 18 u8 *pixels; 19 } symbol; 20 21 typ struct { 22 bool pixel; 23 u32 height; 24 symbol chars[127]; 25 u8 *pixels; 26 } twidfont; 27 28 bool parseTwidFont(smallArrayt *fontFile, twidfont *font) { 29 30 // scan symbol sizes 31 // create pixel buffer 32 // copy font to pixel buffer 33 34 // scan symbol sizes 35 u32 totalWidth = 0; 36 u8 index = 0; 37 bool scanHeight = yes; 38 char *status = "pixel"; 39 iter(fontFile, L) { 40 castS(l, L); 41 if (eqG(status, "in char")) { 42 if (font->chars[index].width == 0) { 43 font->chars[index].width = indexOfG(l, "@"); 44 totalWidth += font->chars[index].width; 45 } 46 if (scanHeight) inc font->height; 47 if (endsWithG(l, "@@")) { 48 // char is finished 49 scanHeight = no; 50 status = "define char"; 51 continue; 52 } 53 } 54 if (eqG(status, "define char")) { 55 defineChar: 56 index = ssGet(l)[0]; 57 status = "in char"; 58 } 59 if (eqG(status, "pixel")) { 60 if (ssGet(l)[0] == '#') continue; // comment at the begining 61 font->pixel = eqG(l, "pixel"); 62 if (not font->pixel) goto defineChar; // already define char 63 status = "define char"; 64 } 65 } 66 //logVarG(totalWidth); 67 68 // create pixel buffer 69 font->pixels = malloc(font->height * totalWidth); 70 71 // copy font to pixel buffer 72 u8 *symbolStart = font->pixels; 73 u8 *p; // pointer for copying symbol pixel data 74 status = "pixel"; 75 iter(fontFile, L) { 76 castS(l, L); 77 if (eqG(status, "in char")) { 78 if (!font->chars[index].pixels) { 79 // set pointer in pixel buffer for symbol 80 font->chars[index].pixels = symbolStart; 81 p = symbolStart; 82 symbolStart += font->height * font->chars[index].width; 83 } 84 memcpy(p, ssGet(l), font->chars[index].width); 85 p += font->chars[index].width; 86 if (endsWithG(l, "@@")) { 87 // char is finished 88 scanHeight = no; 89 status = "define char"; 90 continue; 91 } 92 } 93 if (eqG(status, "define char")) { 94 defineChar2: 95 index = ssGet(l)[0]; 96 status = "in char"; 97 } 98 if (eqG(status, "pixel")) { 99 if (ssGet(l)[0] == '#') continue; // comment at the begining 100 font->pixel = eqG(l, "pixel"); 101 if (not font->pixel) goto defineChar2; // already define char 102 status = "define char"; 103 } 104 } 105 106 ret yes; 107 } 108 109 void freeTwidFont(twidfont *font) { 110 if (font) freen(font->pixels); 111 } 112 113 // bit 0 is the lower line 114 // bit 1 is the upper line 115 // ▄ 0x2584 ▀ 0x2580 █ 0x2588 116 rune halfBlockRunes[] = {' ', 0x2584/*▄*/, 0x2580/*▀*/, 0x2588/*█*/}; 117 118 void showStringHalfblock(twidfont *font, char *string) { 119 if (!font or !font->pixel) ret; 120 size_t len = lenG(string); 121 if (!len) ret; 122 123 u32 totalWidth = 0; // in blocks 124 range(i, len) { 125 totalWidth += font->chars[string[i]].width; 126 } 127 128 u8 *pixels = malloc(font->height * totalWidth); 129 u32 x = 0; // start of next character in pixels 130 131 range(i, len) { 132 if (!font->chars[string[i]].width) continue; // font symbol unavailable 133 // copy symbol to buffer 134 u8 *p = font->chars[string[i]].pixels; 135 range(ii, font->height) { 136 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 137 p += font->chars[string[i]].width; 138 } 139 140 x+= font->chars[string[i]].width; 141 } 142 143 u8 *p = pixels; 144 rangeFromStep(j, 1, font->height, 2) { 145 u8 block = 0; 146 range(i, totalWidth) { 147 block = (*(p + i)== ' ' ? 0 : 2) | (*(p + i + totalWidth)== ' ' ? 0 : 1); 148 //printf(halfBlocks[block]); 149 tb_change_cell(i, j / 2, halfBlockRunes[block], TB_WHITE, TB_BLACK); 150 } 151 p += totalWidth * 2; 152 } 153 if (font->height & 1) { 154 u8 block = 0; 155 range(i, totalWidth) { 156 block = (*(p + i)== ' ' ? 0 : 2); 157 //printf(halfBlocks[block]); 158 tb_change_cell(i, font->height / 2, halfBlockRunes[block], TB_WHITE, TB_BLACK); 159 } 160 } 161 162 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 163 /* * ( totalWidth) */ 164 /* * sizeof(u32)); */ 165 /* free(buffer); */ 166 free(pixels); 167 } 168 169 void showStringHalfblockNoFullBlock(twidfont *font, char *string) { 170 if (!font or !font->pixel) ret; 171 size_t len = lenG(string); 172 if (!len) ret; 173 174 u32 totalWidth = 0; // in blocks 175 range(i, len) { 176 totalWidth += font->chars[string[i]].width; 177 } 178 179 u8 *pixels = malloc(font->height * totalWidth); 180 u32 x = 0; // start of next character in pixels 181 182 range(i, len) { 183 if (!font->chars[string[i]].width) continue; // font symbol unavailable 184 // copy symbol to buffer 185 u8 *p = font->chars[string[i]].pixels; 186 range(ii, font->height) { 187 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 188 p += font->chars[string[i]].width; 189 } 190 191 x+= font->chars[string[i]].width; 192 } 193 194 u32 colors[] = {0x4495cc, 0x6baddb, 0xcceafe, 0xd4eefd, 0x896215, 0xd49b33, 0xe3b248, 0xfee2a4}; 195 196 u8 *p = pixels; 197 rangeFromStep(j, 1, font->height, 2) { 198 range(i, totalWidth) { 199 tb_change_cell(i, j / 2, halfBlockRunes[2], *(p + i)== ' ' ? 0 : colors[j-1], *(p + i + totalWidth)== ' ' ? 0 : colors[j]); 200 } 201 printf(RST); 202 put; 203 p += totalWidth * 2; 204 } 205 if (font->height & 1) { 206 range(i, totalWidth) { 207 tb_change_cell(i, font->height / 2, halfBlockRunes[2], *(p + i)== ' ' ? 0 : colors[font->height-1], TB_DEFAULT); 208 } 209 put; 210 } 211 212 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 213 /* * ( totalWidth) */ 214 /* * sizeof(u32)); */ 215 /* free(buffer); */ 216 free(pixels); 217 } 218 219 // bits 3|2 220 // --- 221 // 1|0 222 // ▗ 0x2597 ▖ 0x2596 ▄ 0x2584 ▝ 0x259D ▐ 0x2590 ▞ 0x259E ▟ 0x259F ▘ 0x2598 223 // ▚ 0x259A ▌ 0x258C ▙ 0x2599 ▀ 0x2580 ▜ 0x259C ▛ 0x259B █ 0x2588 224 rune quadrantRunes[] = {' ', 0x2597/*▗*/, 0x2596/*▖*/, 0x2584/*▄*/, 0x259D/*▝*/, 0x2590/*▐*/, 0x259E/*▞*/, 0x259F/*▟*/, 0x2598/*▘*/, 225 0x259A/*▚*/, 0x258C/*▌*/, 0x2599/*▙*/, 0x2580/*▀*/, 0x259C/*▜*/, 0x259B/*▛*/, 0x2588/*█*/}; 226 227 void showStringQuadrant(twidfont *font, char *string) { 228 if (!font or !font->pixel) ret; 229 size_t len = lenG(string); 230 if (!len) ret; 231 232 u32 totalWidth = 0; // in blocks 233 range(i, len) { 234 totalWidth += font->chars[string[i]].width; 235 } 236 237 u8 *pixels = malloc(font->height * totalWidth); 238 u32 x = 0; // start of next character in pixels 239 240 range(i, len) { 241 if (!font->chars[string[i]].width) continue; // font symbol unavailable 242 // copy symbol to buffer 243 u8 *p = font->chars[string[i]].pixels; 244 range(ii, font->height) { 245 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 246 p += font->chars[string[i]].width; 247 } 248 249 x+= font->chars[string[i]].width; 250 } 251 252 u8 *p = pixels; 253 rangeFromStep(j, 1, font->height, 2) { 254 u8 block = 0; 255 rangeFromStep(i, 1, totalWidth, 2) { 256 block = (*(p + i-1) == ' ' ? 0 : 8) 257 | (*(p + i) == ' ' ? 0 : 4) 258 | (*(p + i-1 + totalWidth) == ' ' ? 0 : 2) 259 | (*(p + i + totalWidth) == ' ' ? 0 : 1); 260 //printf(quadrants[block]); 261 tb_change_cell(i / 2, j / 2, quadrantRunes[block], TB_WHITE, TB_BLACK); 262 } 263 if (totalWidth & 1) { 264 block = (*(p + totalWidth-1) == ' ' ? 0 : 8) 265 | (*(p + totalWidth-1 + totalWidth) == ' ' ? 0 : 2); 266 //printf(quadrants[block]); 267 tb_change_cell(totalWidth / 2, j / 2, quadrantRunes[block], TB_WHITE, TB_BLACK); 268 } 269 p += totalWidth * 2; 270 } 271 if (font->height & 1) { 272 u8 block = 0; 273 rangeFromStep(i, 1, totalWidth, 2) { 274 block = (*(p + i-1) == ' ' ? 0 : 8) 275 | (*(p + i) == ' ' ? 0 : 4); 276 //printf(quadrants[block]); 277 tb_change_cell(i / 2, font->height / 2, quadrantRunes[block], TB_WHITE, TB_BLACK); 278 } 279 if (totalWidth & 1) { 280 block = (*(p + totalWidth-1) == ' ' ? 0 : 8); 281 //printf(quadrants[block]); 282 tb_change_cell(totalWidth / 2, font->height / 2, quadrantRunes[block], TB_WHITE, TB_BLACK); 283 } 284 } 285 286 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 287 /* * ( totalWidth/2 + totalWidth&1) */ 288 /* * sizeof(u32)); */ 289 /* free(buffer); */ 290 free(pixels); 291 } 292 293 void tb_change_cell_with_limit(int x, int y, int xlimit, int ylimit, uint32_t ch, uint32_t fg, uint32_t bg) { 294 if (x >= xlimit or y >= ylimit) ret; 295 tb_change_cell(x, y, ch, fg, bg); 296 } 297 298 void showStringQuadrantWithLimit(int x, int y, uint32_t fg, uint32_t bg, int wlimit, int hlimit, twidfont *font, char *string) { 299 if (!font or !font->pixel) ret; 300 size_t len = lenG(string); 301 if (!len) ret; 302 303 wlimit += x; 304 hlimit += y; 305 306 u32 totalWidth = 0; // in blocks 307 range(i, len) { 308 totalWidth += font->chars[string[i]].width; 309 } 310 311 u8 *pixels = malloc(font->height * totalWidth); 312 u32 nextChar = 0; // start of next character in pixels 313 314 range(i, len) { 315 if (!font->chars[string[i]].width) continue; // font symbol unavailable 316 // copy symbol to buffer 317 u8 *p = font->chars[string[i]].pixels; 318 range(ii, font->height) { 319 memcpy(pixels + nextChar + ii * totalWidth, p, font->chars[string[i]].width); 320 p += font->chars[string[i]].width; 321 } 322 323 nextChar += font->chars[string[i]].width; 324 } 325 326 u8 *p = pixels; 327 rangeFromStep(j, 1, font->height, 2) { 328 u8 block = 0; 329 rangeFromStep(i, 1, totalWidth, 2) { 330 block = (*(p + i-1) == ' ' ? 0 : 8) 331 | (*(p + i) == ' ' ? 0 : 4) 332 | (*(p + i-1 + totalWidth) == ' ' ? 0 : 2) 333 | (*(p + i + totalWidth) == ' ' ? 0 : 1); 334 //printf(quadrants[block]); 335 tb_change_cell_with_limit(i / 2 + x, j / 2 + y, wlimit, hlimit, quadrantRunes[block], fg, bg); 336 } 337 if (totalWidth & 1) { 338 block = (*(p + totalWidth-1) == ' ' ? 0 : 8) 339 | (*(p + totalWidth-1 + totalWidth) == ' ' ? 0 : 2); 340 //printf(quadrants[block]); 341 tb_change_cell_with_limit(totalWidth / 2 + x, j / 2 + y, wlimit, hlimit, quadrantRunes[block], fg, bg); 342 } 343 p += totalWidth * 2; 344 } 345 if (font->height & 1) { 346 u8 block = 0; 347 rangeFromStep(i, 1, totalWidth, 2) { 348 block = (*(p + i-1) == ' ' ? 0 : 8) 349 | (*(p + i) == ' ' ? 0 : 4); 350 //printf(quadrants[block]); 351 tb_change_cell_with_limit(i / 2 + x, font->height / 2 + y, wlimit, hlimit, quadrantRunes[block], fg, bg); 352 } 353 if (totalWidth & 1) { 354 block = (*(p + totalWidth-1) == ' ' ? 0 : 8); 355 //printf(quadrants[block]); 356 tb_change_cell_with_limit(totalWidth / 2 + x, font->height / 2 + y, wlimit, hlimit, quadrantRunes[block], fg, bg); 357 } 358 } 359 360 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 361 /* * ( totalWidth/2 + totalWidth&1) */ 362 /* * sizeof(u32)); */ 363 /* free(buffer); */ 364 free(pixels); 365 } 366 367 int main(int ARGC, char** ARGV) { 368 369 argc = ARGC; argv = ARGV; 370 371 initLibsheepy(ARGV[0]); 372 setLogMode(LOG_VERBOSE); 373 //openProgLogFile(); 374 //setLogSymbols(LOG_UTF8); 375 //disableLibsheepyErrorLogs; 376 377 cleanAllocateSmallArray(fontFile); 378 cleanCharP(fontname) = expandHome(FONT_DIR"PressStart2P.twidf"); 379 readFileG(fontFile, fontname); 380 381 twidfont font = init0Var; 382 383 parseTwidFont(fontFile, &font); 384 385 int r = tb_init(); 386 if (r) { 387 logE("tb_init() failed with error code %d\n", r); 388 XFailure; 389 } 390 391 tb_select_output_mode(TB_OUTPUT_TRUECOLOR); 392 393 void draw_all(void) { 394 tb_clear(); 395 //tb_change_cell(/*x*/ 2, /*y*/ 2, '@', TB_GREEN, TB_BLACK); 396 //showStringQuadrant(&font, "Press Start"); 397 //showStringHalfblock(&font, "Press Start"); 398 //showStringHalfblockNoFullBlock(&font, "Press Start"); 399 showStringQuadrantWithLimit(10, 10, TB_GREEN, TB_BLUE, 30, 3, &font, "Press Start"); 400 tb_present(); 401 } 402 403 draw_all(); 404 405 struct tb_event ev; 406 while (tb_poll_event(&ev)) { 407 switch (ev.type) { 408 case TB_EVENT_KEY: 409 switch (ev.key) { 410 case TB_KEY_ESC: 411 goto done; 412 } 413 if (ev.ch == 'q') goto done; 414 415 tb_stringf(2, 30, TB_WHITE, TB_DEFAULT, "key code: %5d, char: %5d, mod: %5d", ev.key, ev.ch, ev.mod); 416 break; 417 case TB_EVENT_RESIZE: 418 draw_all(); 419 break; 420 } 421 tb_present(); 422 } 423 done: 424 freeTwidFont(&font); 425 tb_shutdown(); 426 } 427 // vim: set expandtab ts=2 sw=2: