tschak909 / platotermamiga

PLATOTerm for the Commodore-Amiga
GNU General Public License v3.0
8 stars 4 forks source link

Implement text output. #3

Closed tschak909 closed 5 years ago

tschak909 commented 5 years ago

The relevant code is screen_char_draw() in src/screen.c

Currently, there is an 8x12 font that's sitting in src/font.h, this is for 640x400 displays.

There will ostensibly be other fonts, e.g.:

Each of these fonts is defined as a 1bpp bitmap.

I am thinking that using BltBitMapRastPort() is the right thing to do, but it doesn't natively allow you to specify which bitplanes to blit to, so, I was thinking:

or if a better way can be done, then great.

I first saw a problem when I ran PLATOTerm in 1.3, because the swapped foreground/background default palettes, the output text became black under 1.3.

The original code for outputting text for PLATOTerm64 was thus:

/**
 * screen_char_draw(Coord, ch, count) - Output buffer from ch* of length count as PLATO characters
 */
void screen_char_draw(padPt* Coord, unsigned char* ch, unsigned char count)
{
  int16_t offset; /* due to negative offsets */
  uint16_t x;      /* Current X and Y coordinates */
  uint16_t y;
  uint16_t* px;   /* Pointers to X and Y coordinates used for actual plotting */
  uint16_t* py;
  uint8_t i; /* current character counter */
  uint8_t a; /* current character byte */
  uint8_t j,k; /* loop counters */
  int8_t b; /* current character row bit signed */
  uint8_t width=FONT_SIZE_X;
  uint8_t height=FONT_SIZE_Y;
  uint16_t deltaX=1;
  uint16_t deltaY=1;
  uint8_t mainColor=1;
  uint8_t altColor=0;
  uint8_t *p;
  uint8_t* curfont;

  switch(CurMem)
    {
    case M0:
      curfont=font;
      offset=-32;
      break;
    case M1:
      curfont=font;
      offset=64;
      break;
    case M2:
      curfont=fontm23;
      offset=-32;
      break;
    case M3:
      curfont=fontm23;
      offset=32;      
      break;
    }

  if (CurMode==ModeRewrite)
    {
      altColor=0;
    }
  else if (CurMode==ModeInverse)
    {
      altColor=1;
    }

  if (CurMode==ModeErase || CurMode==ModeInverse)
    mainColor=0;
  else
    mainColor=1;

  tgi_setcolor(mainColor);

#ifdef __ATARI__
  x=mul0625((Coord->x&0x1FF));
  y=mul0375((Coord->y+15^0x1FF)&0x1FF);
#else
  x=scalex[(Coord->x&0x1FF)];
  y=scaley[(Coord->y)+15&0x1FF];
#endif

  if (FastText==padF)
    {
      goto chardraw_with_fries;
    }

  /* the diet chardraw routine - fast text output. */

  for (i=0;i<count;++i)
    {
      a=*ch;
      ++ch;
      a+=offset;
      p=&curfont[fontptr[a]];

      for (j=0;j<FONT_SIZE_Y;++j)
    {
      b=*p;

      for (k=0;k<FONT_SIZE_X;++k)
        {
          if (b<0) /* check sign bit. */
        {
          tgi_setcolor(mainColor);
          tgi_setpixel(x,y);
#ifdef __C64_COLOR__
          x_coord=x-4;
          y_coord=y;
          color_transform(); // take x_coord/y_coord, return offset into color ram in colorpt.
          asm("sei");          // stop interrupts.
          asm("lda $01");      // value of kernal banking address
          asm("pha");          // push onto stack
          asm("and #$FC");     // AND off last two bits (to page out kernal and basic roms)
          asm("sta $01");      // and pop back into kernal banking address
          POKE(0xD000+colorpt,(current_foreground << 4) | PEEK(0xD000+colorpt));   // Plop on new color ram value
          asm("pla");          // Pop old kernal banking value off stack back into A
          asm("sta $01");      // store
          asm("cli");          // and turn back on interrupts, like nothing ever happened.
#endif
        }

          ++x;
          b<<=1;
        }

      ++y;
      x-=width;
      ++p;
    }

      x+=width;
      y-=height;
    }

  return;

 chardraw_with_fries:
  if (Rotate)
    {
      deltaX=-abs(deltaX);
      width=-abs(width);
      px=&y;
      py=&x;
    }
    else
    {
      px=&x;
      py=&y;
    }

  if (ModeBold)
    {
      deltaX = deltaY = 2;
      width<<=1;
      height<<=1;
    }

  for (i=0;i<count;++i)
    {
      a=*ch;
      ++ch;
      a+=offset;
      p=&curfont[fontptr[a]];

      for (j=0;j<FONT_SIZE_Y;++j)
    {
      b=*p;

      if (Rotate)
        {
          px=&y;
          py=&x;
        }
      else
        {
          px=&x;
          py=&y;
        }

      for (k=0;k<FONT_SIZE_X;++k)
        {
          if (b<0) /* check sign bit. */
        {
          tgi_setcolor(mainColor);
          if (ModeBold)
            {
              tgi_setpixel(*px+1,*py);
              tgi_setpixel(*px,*py+1);
              tgi_setpixel(*px+1,*py+1);
            }
          tgi_setpixel(*px,*py);
        }
          else
        {
          if (CurMode==ModeInverse || CurMode==ModeRewrite)
            {
              tgi_setcolor(altColor);
              if (ModeBold)
            {
              tgi_setpixel(*px+1,*py);
              tgi_setpixel(*px,*py+1);
              tgi_setpixel(*px+1,*py+1);
            }
              tgi_setpixel(*px,*py); 
            }
        }

          x += deltaX;
          b<<=1;
        }

      y+=deltaY;
      x-=width;
      ++p;
    }

      Coord->x+=width;
      x+=width;
      y-=height;
    }

  return;

}

So as you can see, there are a few different text states:

Text writing modes

Bold mode

Reverse

Rotate

The glyphs can be pulled from one of four text memories: