heartbeat

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: