- Reimplement font loading/drawing
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 10 Apr 2022 00:28:31 +0000 (00:28 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 10 Apr 2022 00:28:31 +0000 (00:28 +0000)
- Cleanup TODO

MATT/TODO.txt
hacks/analogterm-main.c
hacks/analogterm.c
hacks/analogterm.h

index d53991d..89f68f7 100644 (file)
@@ -3,6 +3,8 @@ BUILD
 - make
 
 TODO
+- Maybe cleanup code checking boundaries, using max or other similar
+  macros or inline functions.
 - When blinking and double-underline, the line doesn't blink.
 - Italics is currently mapped to inverse, like in rxvt.
 - There's an apparent bug in utf8wc.c's utf8_split() function.
@@ -11,7 +13,8 @@ TODO
   See L1 and L2 usage with strncpy(3).
 - vt100 double line? $ printf '\033#3Foo\n\033#4Foo\n'
   It seems that this is not used with modern terminfo/curses
-  applications.
+  applications.  Xterm itself appears to only support it with
+  certain fonts.
 - Jump/fast scroll, smooth/slow scroll (one line at a time).
 - h/l 1: Application Cursor Keys
 - O_o, in xterm: \033[5 q , [1 q , [2 q , [3 q , [4 q , 5, 6...
@@ -19,41 +22,12 @@ TODO
 - Cursor color '\033]12;green\007' quite interestingly labels work.
   Numerics not always?
 - Maybe line position relative/absolute (d/e vpa/vpr?)
-- Verify if in xterm when scrolling blank lines really have color
-  disabled.  Since pseudocolor support was added, vifm seems to have
-  strange color problems in relation to scrolling.
-  Confirmed that xterm uses the background color when creating blank
-  spaces.  Analogterm improved but still some oddities with vifm to
-  fix, related to scrolling.
-- With the current pseudocolors impementation, the current cursor
-  position in sc(1) is no longer visible...  Ignoring black bg
-  color improves things for now.
-  Update: the cursor no longer uses text blinking support.  The custom
-  implementation fixes this.
 - Now that pseudocolors are implemented, dialog(1) and possibly
   other programs look strange.
 - When under tmux/screen, dialog(1) attempts to use higher characters
   rather than DEC Special Graphics.  May perhaps be configurable...
-- When under tmux, dialog(1) no longer uses DEC Special Graphics.
   Some programs also use those extended characters like wordgrinder.
-- Interestingly, since we're a monochrome terminal, when using
-  "xterm" for $TERM tmux uses color for copy-paste text selection
-  and appears to have no option to change that.  On the other hand,
-  if using "xtermm" for xterm-monochrome, tmux then correctly uses
-  the inverse attribute.  This also affects the status bar if colors
-  are used.  However, vim doesn't automatically switch to t_Co=0, and
-  when told so, no longer behaves the same, it strangely no longer
-  uses underline.  When using dialog(1), the colors appear inversed
-  with "xtermm".  With "xtermm" dialog(1) also no longer uses DEC
-  Special Graphics.  Under Linux via ssh it seemingly attempts to use
-  it unsuccessfully since the common chars like q are used, and it's
-  in inverse mode.  Verify if inverse works with the gfx mode.  The
-  terminfo entry explains everything.  Apparently it's an unsupported
-  historical variant.
-  Various key sequences are not properly supported, smacs (DEC
-  Special Graphics) issues ^N instead of \E(0, underline mode is
-  unsupported, etc.  Let's use xterm and simulate pseudocolors instead.
-  It would still be interesting to carefully look at the entry to determine
+- It would still be interesting to carefully look at the entry to determine
   what affects the behavior of applications, like determining if colors are
   available or not.  The "colors" terminfo entry depends on the terminfo entry
   set in $TERM and is not a terminal-related code, only a number.  This means
@@ -162,26 +136,20 @@ TODO
   termcap/terminfo and applications degrade.
 - Add explicit TERM setting, seems to be in generic xscreensaver
   command handling code.
-- Maybe try to implement smooth scrolling and line/char delete/insert
-  - xterm's line insert functionality seems to not be implemented yet
-    (L).  This explains why scrolling up in more/less fails and only
-    updates the first row.  Terminfo db has il1 and il <param>.
-    Line insertion is basically reverse-scrolling starting at a
-    particular offset and that can extend the wanted number of
-    lines.  The scrolling window should be restricted to the field
-    if any is configured.
-  - Plus there's rmir/smir to enable/disable automatic insert mode
-    ([4l, [4h)...
-  - Then kich1=\E[2~, the insert key.
+- Maybe implement smooth scrolling.  This would be restricted to the case
+  where the cursor is at the bottom and one line is scrolled at a time only.
+  In screen/tmux, this means that the status bar must either be disabled or at
+  the top rather than at the bottom.  It may still possibly behave oddly when
+  at top, to test.  The analog overscan emulation interestingly allows to have
+  a sliding window if we use an offset that is reset when scrolling and that
+  the main loop redjusts gradually.
+  Well, perhaps that smooth scrolling in the other direction could also be
+  allowed under the same reverse conditions.
+- rmir/smir to enable/disable automatic insert mode ([4l, [4h)...
+- kich1=\E[2~, the insert key.
 - Cleanup headerfile, removing unnecessary prototypes/definitions
-- Add common graphics characters to make frames.  Lynx uses some
-  to implement its scrollbar.  Wordgrinder also uses some.
-  This entry seems redundant.
 - Maybe support read-only text/regions
 - Maybe support text windows (?)
-- Delete acts like backspace but should delete
-  This is inverted in utils/textclient.c textclient_putc()
-  This entry seems redundant.
 - Isolate code outside of xscreensaver, make a GNUmakefile.
   Ironically the result will be more portable on common unix.
   And much cleaner once consolidated.
@@ -197,12 +165,14 @@ TODO
   implement or swallow.  Also, xterm uses 0x9B too not only ESC.
 - Tack seems to be a decent program for terminal testing, other
   than vttest.
-- ninvaders is very slow and not very responsive.  This could serve
-  to work on some optimizations.  It's also possible that it has
-  to do with user input handling.  When reducing refresh rate like
-  with 0 delay using more CPU, it's more responsive.
-  This should be configurable.
+- ninvaders has good animation but its input is very responsive.
+  This could serve to work on some optimizations.
+  Input handling could probably be improved and considered
+  prioritary.  When increasing the refresh rate like with 0 delay
+  using more CPU, it's more responsive.  This should be configurable.
 
+
+CONTROLS
 From the xanalogtv man page:
        Notable X resources supported include the following which correspond to
        standard TV controls: analogTVTint, analogTVColor, analogTVBrightness,
@@ -229,10 +199,7 @@ the TG-1, thereby disabling the TG-1's own 31500 Hz reference
 oscillator."
 https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Ntsc_channel.svg/800px-Ntsc_channel.svg.png
 
-$ hacks/analogterm -fast -geometry 1024x768 -program /bin/sh -tv-brightness 3 -tv-contrast 100
-$ hacks/analogterm -fast -geometry 1024x768 -program /bin/sh -tv-brightness 0 -tv-contrast 70
--geometry 1364x1024
-
+FONT
 https://retrocomputing.stackexchange.com/questions/17312/did-any-european-computers-use-10-line-fonts
 "The Videx Videoterm 80 column card for the Apple II (very different
 from the 80 column display on the Apple //e) used an 6845 that had
@@ -246,12 +213,23 @@ column card I had didn't aloow this).  So it looks like your
 sentiment of "to get 25 text lines, an 8x10 font would be ideal"
 was not shared by everyone ... though you could have burned your
 own EEPROM to get such a font."
-"
 
 
+
+VIM
+Vim can be told to not use color with :set t_Co=0 in which case it falls back
+to attributes like bold/underline/inverse.  However, some functionality is
+lost.  Unless t_Co=8 or over,  :hi MatchParen cterm=underline  for instance
+still doesn't work.  This means that for ideal vim support, a colorscheme
+designed for monochrome helps.
+
+
+USAGE EXAMPLES
+
+hacks/analogterm -fast -geometry 1024x768 -program /bin/sh -tv-brightness 3 -tv-contrast 100
+hacks/analogterm -fast -geometry 1024x768 -program /bin/sh -tv-brightness 0 -tv-contrast 70
 hacks/analogterm -fast -geometry 1364x1024 -program /bin/sh -tv-color 10
 
-1152x921 is approx 12" 5/4 on a 24" monitor
 912x720 is approx 12" 5/4 old display on a modern 24" monitor.
 
 hacks/analogterm -fast -geometry 1364x1024 -program /bin/sh -tv-color 0
@@ -259,4 +237,4 @@ hacks/analogterm -fast -geometry 1364x1024 -program /bin/sh -tv-color 0 -tv-brig
 hacks/analogterm -fast -geometry 1364x1024 -program /bin/sh -tv-color 0 -tv-brightness 2 -tv-contrast 140 -del -bs
 
 hacks/analogterm -geometry 1364x1024 -bs
-stty then often useful to set ERASE properly (to fix).
+stty erase ^H   then often useful to set ERASE properly (to fix).
index 6e82ed0..50bafe2 100644 (file)
@@ -1116,6 +1116,8 @@ analogterm_draw (Display *dpy, Window window, void *closure)
    * CPU time.  Then 1 and over immediately affect performance.
    * Running cursor effects are also more noticeable at 5000 and lower.
    * This should be user-configurable.
+   * After more changes it is unclear if 0 gives better performance, sometimes
+   * it seems to be the contrary.
    */
   return /*5000*//*20000*/1; /* Note: use 0 for faster response like for games */
 #endif
index c5ddb5e..47f6550 100644 (file)
@@ -74,7 +74,6 @@ at_move(analogterm_state_t *st, int dx, int dy, int sx, int sy, int len)
 void
 at_clear(analogterm_state_t *st, int x, int y, int len)
 {
-       int f, t;
        uint16_t *mptr, *tptr;
 
        (void)memset(&st->textlines_char[y][x], ' ', len);
@@ -136,7 +135,7 @@ at_drawcursor(analogterm_sim_t *sim)
         * XXX
         * - This memory design is very inefficient
         * - Should probably use a well-defined range instead of full cycle
-        * - Blinking speed should rely in a configurable timer
+        * - Blinking speed should rely on a configurable timer
         */
        for (y = 0; y < 8; y++) {
                pp = &sim->inp->signal[(ANALOGTV_TOP+3) + (8 * st->cursy) + y]
@@ -174,6 +173,12 @@ at_scroll_range(analogterm_state_t *st, int offset)
 {
        int y;
 
+       /* XXX */
+       /*
+       if (st->cursy == 24 && offset == -1)
+               (void)fprintf(stderr, "Smooth scroll possible.\n");
+       */
+
        /* Nothing to do */
        if (offset == 0)
                return;
@@ -224,7 +229,7 @@ at_printc_1(analogterm_state_t *st, char c, uint16_t m, int scroll_p)
 
   if (c == '\n')                      /* ^J == NL */
     {
-      if (st->cursy==st->scroll_bottom)
+      if (st->cursy == st->scroll_bottom)
         {
           if (scroll_p)
             at_scroll(st);
@@ -233,27 +238,26 @@ at_printc_1(analogterm_state_t *st, char c, uint16_t m, int scroll_p)
         {
           st->cursy++;
         }
-      st->cursx=0;
+      st->cursx = 0;
     }
   else if (c == 014)                  /* ^L == CLS, Home */
     {
       at_cls(st);
-      at_goto(st,0,0);
+      at_goto(st, 0, 0);
     }
   else if (c == '\t')                 /* ^I == tab */
     {
-      at_goto(st, st->cursy, (st->cursx+8)&~7);
+      at_goto(st, st->cursy, (st->cursx + 8) & ~7);
     }
   else if (c == 010)                  /* ^H == backspace */
-    /* XXX May not behave standardly, to check.  Could use at_clear(). */
+    /* XXX May not behave standardly, to check. */
     {
-      st->textlines_char[st->cursy][st->cursx] = ' ';
-      st->textlines_mode[st->cursy][st->cursx] = m & TMODE_BGCOLOR;
-      at_goto(st, st->cursy, st->cursx-1);
+      at_clear(st, st->cursx, st->cursy, 1);
+      at_goto(st, st->cursy, st->cursx - 1);
     }
   else if (c == '\r')                 /* ^M == CR */
     {
-      st->cursx=0;
+      st->cursx = 0;
     }
   else
     {
@@ -261,14 +265,14 @@ at_printc_1(analogterm_state_t *st, char c, uint16_t m, int scroll_p)
       st->textlines_char[st->cursy][st->cursx] = c;
       st->textlines_mode[st->cursy][st->cursx] = m;
       st->cursx++;
-      if (st->cursx==80) {
-        if (st->cursy==st->scroll_bottom) {
+      if (st->cursx == 80) {
+        if (st->cursy == st->scroll_bottom) {
           if (scroll_p)
             at_scroll(st);
         } else {
           st->cursy++;
         }
-        st->cursx=0;
+        st->cursx = 0;
       }
     }
 }
@@ -327,36 +331,41 @@ at_cls(analogterm_state_t *st)
 #include "images/analogtermfont.xbm"
 #include "images/analogtermgfxfont.xbm"
 
-static void
-at_make_font(analogterm_sim_t *sim)
-{
-  Pixmap text_pm = XCreatePixmapFromBitmapData (sim->dpy, sim->window,
-                                                (char *) analogterm_font_bits,
-                                                analogterm_font_width,
-                                                analogterm_font_height,
-                                                1, 0, 1);
-  if (analogterm_font_width != 96*7) abort();
-  if (analogterm_font_height != 8) abort();
-  sim->text_im[0] = XGetImage(sim->dpy, text_pm, 0, 0, 
-                           analogterm_font_width, analogterm_font_height,
-                           ~0L, ZPixmap);
-  XFreePixmap(sim->dpy, text_pm);
-}
 
+/*
+ * XXX So many contortions just to get at the bits, that we could probably
+ * directly use from the bits ourselves...  In any case, this does the
+ * preconversion at initialization for now.
+ */
 static void
-at_make_font_gfx(analogterm_sim_t *sim)
+at_make_font(analogterm_sim_t *sim, int fi, char *bits, unsigned int width,
+    unsigned int height)
 {
-  Pixmap text_pm = XCreatePixmapFromBitmapData (sim->dpy, sim->window,
-                                                (char *) analogtermgfx_font_bits,
-                                                analogtermgfx_font_width,
-                                                analogtermgfx_font_height,
-                                                1, 0, 1);
-  if (analogtermgfx_font_width != 96*7) abort();
-  if (analogtermgfx_font_height != 8) abort();
-  sim->text_im[1] = XGetImage(sim->dpy, text_pm, 0, 0, 
-                           analogtermgfx_font_width, analogtermgfx_font_height,
-                           ~0L, ZPixmap);
-  XFreePixmap(sim->dpy, text_pm);
+       Pixmap pm;
+       XImage *xi;
+       unsigned long (*f)[8][7];
+       int c, r, b;
+
+       assert(width == 96 * 7 && height == 8);
+
+       pm = XCreatePixmapFromBitmapData(sim->dpy, sim->window, bits, width,
+           height, 1, 0, 1);
+       xi = XGetImage(sim->dpy, pm, 0, 0, width, height, ~0L, ZPixmap);
+       (void)XFreePixmap(sim->dpy, pm);
+
+       /* Fill structure element with font data */
+       f = sim->text_font[fi];
+       for (c = 0; c < 96; c++) {
+               for (r = 0; r < 8; r++) {
+                       for (b = 0; b < 7; b++)
+                               f[c][r][b] = XGetPixel(xi, (c * 7) + b, r % 8);
+               }
+       }
+
+       /* Strange freeing procedure */
+       free(xi->data);
+       xi->data = NULL;
+       XDestroyImage(xi);
 }
 
 analogterm_sim_t *
@@ -395,8 +404,10 @@ analogterm_start(Display *dpy, Window window, int delay,
   sim->st->scroll_top = 0;
   sim->st->scroll_bottom = 24;         /* XXX Use definition/macro */
 
-  at_make_font(sim);
-  at_make_font_gfx(sim);
+  at_make_font(sim, 0, analogterm_font_bits, analogterm_font_width,
+              analogterm_font_height);
+  at_make_font(sim, 1, analogtermgfx_font_bits, analogtermgfx_font_width,
+              analogtermgfx_font_height);
 
   sim->stepno=0;
   at_goto(sim->st,24,0);
@@ -537,16 +548,7 @@ analogterm_one_frame (analogterm_sim_t *sim)
 
           XClearWindow(sim->dpy, sim->window);
 
-          /* free sim */
-          /* This is from at_make_font */
-          free(sim->text_im[0]->data);
-          sim->text_im[0]->data = 0;
-          XDestroyImage(sim->text_im[0]);
-          free(sim->text_im[1]->data);
-          sim->text_im[1]->data = 0;
-          XDestroyImage(sim->text_im[1]);
-
-          /* And free else */
+          /* Free sim and else */
           analogtv_release(sim->dec);
           free(st);
           free(sim->inp);
@@ -562,13 +564,16 @@ analogterm_one_frame (analogterm_sim_t *sim)
     analogtv_setup_sync(sim->inp, /* XXX 1 */0, 0);
     analogtv_setup_frame(sim->dec);
 
-    for (textrow=0; textrow<25; textrow++) {
+    for (textrow = 0; textrow < 25; textrow++) {
       int row;
-      for (row=textrow*8; row<textrow*8+8; row++) {
+      int rowmul = textrow * 8;
+
+      for (row = rowmul; row < rowmul + 8; row++) {
         signed char *pp;
        int col;
-       int lastrow = row == textrow * 8 + 7;
-       int midrow = row == textrow * 8 + 3;
+       int lastrow = row == rowmul + 7;
+       int midrow = row == rowmul + 4;
+       int rowm = row % 8;
 
         /* First we generate the pattern that the video circuitry shifts out
            of memory. It has a 14.something MHz dot clock, equal to 4 times
@@ -576,13 +581,20 @@ analogterm_one_frame (analogterm_sim_t *sim)
            Each character position, or byte in hires, defines 14 dots, so odd
            and even bytes have different color spaces. So, pattern[0..600]
            gets the dots for one scan line. */
-       /* With 25 lines the offset was changed to 3 to avoid loss */
-       pp=&sim->inp->signal[row+ANALOGTV_TOP+/*4*/3][ANALOGTV_PIC_START+100];
-       for (col=0; col<80; col++) {
+       /*
+        * With 25 lines the offset was changed from 4 to 3 to avoid loss
+        * XXX Interestingly the signal appears to start low enough end end
+        * high enough that it would be possible to implement smooth scrolling
+        * by sliding a window.
+        */
+       pp=&sim->inp->signal[row + ANALOGTV_TOP + 3][ANALOGTV_PIC_START + 100];
+       for (col = 0; col < 80; col++) {
             int rev, level, olevel, iblink;
-            int c = st->textlines_char[textrow][col] & 0xff; /* XXX */
+            int c = st->textlines_char[textrow][col];
            uint16_t m = st->textlines_mode[textrow][col];
-           XImage *im = sim->text_im[(m & TMODE_GFX) != 0 ? 1 : 0];
+           unsigned long (*f)[8][7] =
+               sim->text_font[(m & TMODE_GFX) != 0 ? 1 : 0];
+           unsigned long (*cf)[7];
 
            rev = ((m & (TMODE_INVERSE | TMODE_BGCOLOR)) != 0);
 
@@ -600,6 +612,13 @@ analogterm_one_frame (analogterm_sim_t *sim)
            else
                    iblink = 0;
 
+           /* XXX Restricts to ASCII/DEC Special Graphics */
+           if (c < 32 || c > 126)
+                   c = /* XXX originally space 32 */95;
+           else
+                   c -= 32;
+           cf = f[c];
+
            /*
             * Font is 96 7x8 glyphs including embedded spacing.
             * Virtual resolution is 280x192 but at 80 columns it gives a less
@@ -609,15 +628,13 @@ analogterm_one_frame (analogterm_sim_t *sim)
             * the IBM 3270 one).  This would however require a 720x350
             * resolution.
             */
-            for (i=0; i<7; i++) {
-               unsigned long pix;
+            for (i = 0; i < 7; i++) {
+               unsigned long *cb = cf[rowm], pix;
 
-               if (c < 32 || c > 126)
-                       c = 32;
                if ((m & TMODE_INVISIBLE) != 0)
                        pix = 0;
                else
-                       pix = XGetPixel(im, (c - 32) * 7 + i, row % 8);
+                       pix = cb[i];
 
                if (lastrow &&
                    (m & (TMODE_UNDERLINE | TMODE_DUNDERLINE)) != 0) {
index 8722fe1..e263f78 100644 (file)
@@ -83,7 +83,7 @@ struct analogterm_sim_s {
   Display *dpy;
   Window window;
   XWindowAttributes xgwa;
-  XImage *text_im[CHARSETS];
+  unsigned long text_font[CHARSETS][96][8][7];
 
   struct timeval basetime_tv;
   double curtime;