heartbeat

Simple server monitor system using encrypted messages over udp
git clone https://noulin.net/git/heartbeat.git
Log | Files | Refs | README

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: