/*
  HI65 - a high-level Commodore 65 emulator
  Copyright (C) 2013-2023  Simone Gremmo
  Contact: devilmaster@email.com

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see
  http://www.gnu.org/licenses/gpl.txt
*/

// display.cpp

#include <allegro.h>
#include <cstdio>
#include "f8x8.h"
#include "gdef.h"
#include "pro.h"
#include "var.h"

void Cout(uchar c)
{
 uchar msk,xtimes,ytimes,comparison;
 uint sy,x,y;
 uint add;
 
 if (c>=0xA0)
  c-=64;
 else
  c-=32;
  
 add=c;
 add<<=3; // add*=8;
 for (sy=0; sy<8; sy++) // vertical scan
 {
  y=CharY+sy*yzoom;
  if (!shifted)
   c=f8x8[add++];
  else
   c=f8x8shifted[add++];
  for (ytimes=0; ytimes<yzoom; ytimes++)
  {
   x=CharX;
   msk=0x80;
   while(msk)
   {
    for (xtimes=0; xtimes<xzoom; xtimes++)
    {
     comparison=c&msk;
     if (comparison)
      _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y,forecolor);
     else
      _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y,backcolor);
     x++;
    }
    msk>>=1;
   }
   y++;
  }
 }
 // next access
 CharX+=(xzoom<<3); // CharX+=8*xzoom;
}

void prints(uchar *str)
{
 uchar c;
 
 // acquire_screen();
 while ((c=*str++)!=0)
  Cout(c);
 // release_screen();
}

void printn(ulong number) // it prints long integer numbers
{
 uchar asciinumber[50];
 uchar i,shiftedbak,howmanydigits;

 shiftedbak=shifted;
 if (shifted)
  shifted=0;
 howmanydigits=sprintf((char *)asciinumber,"%d",number);
 for (i=0; i<howmanydigits; i++)
  Cout(asciinumber[i]);
 shifted=shiftedbak;
}

void printn(double number) // it prints double precision floating point numbers
{
 uchar asciinumber[50];
 uchar i,shiftedbak,howmanydigits;

 shiftedbak=shifted;
 if (shifted)
  shifted=0;
 howmanydigits=sprintf((char *)asciinumber,"%f",number);
 for (i=0; i<howmanydigits; i++)
  Cout(asciinumber[i]);
 shifted=shiftedbak;
}

void printerror(double error)
{
 uint i, aux, scanned_line_number, scanned_instruction_end, string_end;
 
 if (!trap) // if a trap line has NOT been set, we print the error...
 {
  numvars[ER][0]=error;
  numvars[EL][0]=line_number;
  aux=(uint)(ERRORSTRINGLENGTH*(numvars[ER][0]-1));
 
  Enter();
  if (screentype==65)
   forecolor=makecol(240,0,0);
  // acquire_screen();
  Cout ('?');
  string_end=aux+ERRORSTRINGLENGTH;
  for (i=aux; !(c65basicerrors[i]==' ' && c65basicerrors[i+1]==' ') && i<string_end; i++)
   Cout(c65basicerrors[i]);
  if (i-aux==ERRORSTRINGLENGTH && c65basicerrors[i-1]==' ')
   BackSpace();
  prints((uchar *)" error in ");
  printn((ulong)(numvars[EL][0]));
  if (screentype==65)
   forecolor=makecol(240,240,240);
  // release_screen();
 }
 else // if we do have a trap line, we redirect the execution to that line instead
 {
  // this is a variation of the GOTO code
  if (trap<=line_number)
   pc=0;
 
  do
  {
   // We skip to the end of the instruction
   // If we are at the beginning of the program, we consider the second
   // char (where pc==1) as the end of a hypothetical "instruction #0"
   // otherwise we advance to the actual end of the instruction
   if (!pc)
    pc++;
   else
   {
    while (program[pc])
     pc++;
   }
   scanned_instruction_end=pc;
    
   // We move 3 bytes forward, to "land" on the first byte of the line number
   pc+=3;
  
   // We read the line number (tokenized LSB-first = little endian)
   scanned_line_number=program[pc];
   pc++;
   aux=program[pc];
   aux<<=8;
   scanned_line_number=aux+scanned_line_number;
  
   // The MSB of the line number may be 0 (which would be interpreted
   // as an instruction end) so we move 1 step forward
   pc++;
  }
  while (scanned_line_number<trap);
 
  // Now we found the correct line. We must return to the beginning of
  // the instruction
  pc=scanned_instruction_end+1;
 }
}

void forebackswap(void)
{
 uint copycolor;
 
 copycolor=forecolor;
 forecolor=backcolor;
 backcolor=copycolor;
}

void BackSpace(void)
{
 if (CharX)
  CharX-=(xzoom<<3);
  
 // acquire_screen();
 rectfill(screen,CharX+screen_border_x,CharY+screen_border_y,CharX+(xzoom<<3)+screen_border_x,CharY+(yzoom<<3)+screen_border_y,backcolor);
 // release_screen();
}

void Enter(void)
{
 CharX=0;
 CharY+=yzoom<<3;
 
 if (screen_height==720 || screen_height==1080)
 {
  if (CharY>168*yzoom)
   CharY=0;
 }
 else
 {
  if (CharY>192*yzoom)
   CharY=0;
 }
}

void Tab(void)
{
 uint cx;
 
 cx=CharX/(xzoom<<3); // the # of pixels is converted to the # of characters
 while (cx%10)
  cx++;
  
 CharX=cx*(xzoom<<3); // the # of characters is converted to the # of pixels
}

void _putpixel32_safe(BITMAP *destscreen,uint pointx,uint pointy,uint pointcolor)
{
 if (pointx<screen_width && pointy<screen_height)
  _putpixel32(destscreen,pointx,pointy,pointcolor);
}

void c65draw(uint x, uint y)
{
 uchar i,j,k;
 
 // The main pixel is plotted
 _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y,forecolor);
  
 // Additional pixels must be plotted to simulate different resolutions
 for (j=2; j<7; j++)
 {
  k=j-1;
  if (xzoom>=j)
  {
   for (i=0; i<j; i++)
    _putpixel32_safe(screen,x+screen_border_x+k,y+screen_border_y+i,forecolor);
  }
  if (yzoom>=j)
  {
   for (i=0; i<j; i++)
    _putpixel32_safe(screen,x+screen_border_x+i,y+screen_border_y+k,forecolor);
  }
  if (xzoom>=j && yzoom>=j)
   _putpixel32_safe(screen,x+screen_border_x+k,y+screen_border_y+k,forecolor);
 }
 
 // ORIGINAL IMPLEMENTATION OF THE FOR J CYCLE
 /*
 if (xzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y,forecolor);
 if (yzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+1,forecolor);
 if (xzoom>=2 && yzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+1,forecolor); 
 
 if (xzoom>=3)
 {
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+1,forecolor);
 }
 if (yzoom>=3)
 {
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+2,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+2,forecolor);
 }
 if (xzoom>=3 && yzoom>=3)
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+2,forecolor);
 
 if (xzoom>=4)
 {
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+1,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+2,forecolor);
 }
 if (yzoom>=4)
 {
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+3,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+3,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+3,forecolor);
 }
 if (xzoom>=4 && yzoom>=4)
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+3,forecolor);
  
 if (xzoom>=5)
 {
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+1,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+2,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+3,forecolor);
 }
 if (yzoom>=5)
 {
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+4,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+4,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+4,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+4,forecolor);
 }
  if (xzoom>=5 && yzoom>=5)
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+4,forecolor);
  
 if (xzoom>=6)
 {
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+1,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+2,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+3,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+4,forecolor);
 }
 if (yzoom>=6)
 {
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+5,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+5,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+5,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+5,forecolor);
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+5,forecolor);
 }
 if (xzoom>=5 && yzoom>=5)
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+5,forecolor);
 */
 
 // PARTIALLY OPTIMIZED IMPLEMENTATION
 /*
 if (xzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y,forecolor);
 if (yzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x,y+screen_border_y+1,forecolor);
 if (xzoom>=2 && yzoom>=2)
  _putpixel32_safe(screen,x+screen_border_x+1,y+screen_border_y+1,forecolor); 
  
 if (xzoom>=3)
 {
  for (i=0; i<3; i++)
   _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+i,forecolor);
 }
 if (yzoom>=3)
 {
  for (i=0; i<3; i++)
   _putpixel32_safe(screen,x+screen_border_x+i,y+screen_border_y+2,forecolor);
 }
 if (xzoom>=3 && yzoom>=3)
  _putpixel32_safe(screen,x+screen_border_x+2,y+screen_border_y+2,forecolor);
 
 if (xzoom>=4)
 {
  for (i=0; i<4; i++)
   _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+i,forecolor);
 }
 if (yzoom>=4)
 {
  for (i=0; i<4; i++)
   _putpixel32_safe(screen,x+screen_border_x+i,y+screen_border_y+3,forecolor);
 }
 if (xzoom>=4 && yzoom>=4)
  _putpixel32_safe(screen,x+screen_border_x+3,y+screen_border_y+3,forecolor);
  
 if (xzoom>=5)
 {
  for (i=0; i<5; i++)
   _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+i,forecolor);
 }
 if (yzoom>=5)
 {
  for (i=0; i<5; i++)
   _putpixel32_safe(screen,x+screen_border_x+i,y+screen_border_y+4,forecolor);
 }
 if (xzoom>=5 && yzoom>=5)
  _putpixel32_safe(screen,x+screen_border_x+4,y+screen_border_y+4,forecolor);
  
 if (xzoom>=6)
 {
  for (i=0; i<6; i++)
   _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+i,forecolor);
 }
 if (yzoom>=6)
 {
  for (i=0; i<6; i++)
   _putpixel32_safe(screen,x+screen_border_x+i,y+screen_border_y+5,forecolor);
 }
 if (xzoom>=5 && yzoom>=5)
  _putpixel32_safe(screen,x+screen_border_x+5,y+screen_border_y+5,forecolor);
 */
}

void paletterestore(void)
{
 uint i;
 
 for (i=0; i<256; i+=16)
 {
  palette[0][0+i][0]= c65color[0];  palette[0][0+i][1]= c65color[0];  palette[0][0+i][2]= c65color[0];  // black
  palette[0][1+i][0]= c65color[15]; palette[0][1+i][1]= c65color[15]; palette[0][1+i][2]= c65color[15]; // white
  palette[0][2+i][0]= c65color[15]; palette[0][2+i][1]= c65color[0];  palette[0][2+i][2]= c65color[0];  // red
  palette[0][3+i][0]= c65color[0];  palette[0][3+i][1]= c65color[15]; palette[0][3+i][2]= c65color[15]; // cyan
  palette[0][4+i][0]= c65color[15]; palette[0][4+i][1]= c65color[0];  palette[0][4+i][2]= c65color[15]; // magenta
  palette[0][5+i][0]= c65color[0];  palette[0][5+i][1]= c65color[15]; palette[0][5+i][2]= c65color[0];  // green
  palette[0][6+i][0]= c65color[0];  palette[0][6+i][1]= c65color[0];  palette[0][6+i][2]= c65color[15]; // blue
  palette[0][7+i][0]= c65color[15]; palette[0][7+i][1]= c65color[15]; palette[0][7+i][2]= c65color[0];  // yellow
  palette[0][8+i][0]= c65color[15]; palette[0][8+i][1]= c65color[6];  palette[0][8+i][2]= c65color[0];  // orange
  palette[0][9+i][0]= c65color[10]; palette[0][9+i][1]= c65color[4];  palette[0][9+i][2]= c65color[0];  // brown
  palette[0][10+i][0]=c65color[15]; palette[0][10+i][1]=c65color[7];  palette[0][10+i][2]=c65color[7];  // pink
  palette[0][11+i][0]=c65color[5];  palette[0][11+i][1]=c65color[5];  palette[0][11+i][2]=c65color[5];  // dark gray
  palette[0][12+i][0]=c65color[8];  palette[0][12+i][1]=c65color[8];  palette[0][12+i][2]=c65color[8];  // medium gray
  palette[0][13+i][0]=c65color[9];  palette[0][13+i][1]=c65color[15]; palette[0][13+i][2]=c65color[9];  // light green
  palette[0][14+i][0]=c65color[9];  palette[0][14+i][1]=c65color[9];  palette[0][14+i][2]=c65color[15]; // light blue
  palette[0][15+i][0]=c65color[11]; palette[0][15+i][1]=c65color[11]; palette[0][15+i][2]=c65color[11]; // light gray
 }
}

void simulateloadinstructions(uchar *str, uchar runprogram)
{
 uchar c;
 uchar *other_str;
 
 other_str=str;
 if (runprogram)
 {
  prints((uchar *)"dload ");
  // acquire_screen();
  Cout('"');
  
  if (str[1]==':')
   shifted=1;
  
  while ((c=*str++)!=0)
   Cout(c);
  
  // if the screen type imitates a PET screen, we must NOT return to
  // the unshifted font 
  if (shifted && screentype)
   shifted=0;
   
  Cout('"');
  // release_screen();
  Enter();
 }
 Enter();
 prints((uchar *)"searching for ");
 // acquire_screen();
 
 if (other_str[1]==':')
   shifted=1;
 
 while ((c=*other_str++)!=0)
  Cout(c);
  
 if (shifted && screentype)
   shifted=0;
  
 // release_screen();
 if (!loaderror)
  Ready();
 else
 {
  Enter();
  forecolor=makecol(240,0,0);
  prints((uchar *)"?dos: file not found");
  forecolor=makecol(240,240,240);
 }
}

void Ready(void)
{
 Enter();
 prints((uchar *)"ready.");
 Enter();
}

int startscreen(uchar from_command)
{
 uchar i,factor;
 int gfxerror=0;
#ifdef DEBUG_SCREEN
 size_t actual_size;
 FILE *pFile;
#endif
 
 switch (screen_width)
 {
  case 1280:
  case 1360:
  case 1440:
  case 1600:
       xzoom=2;
       yzoom=4;
       break;
  case 1920:
       xzoom=3;
       yzoom=6;
       break;
  default:
       xzoom=1;
       yzoom=2;
       break;
 }
 
 // The initialization is only done if the function has NOT been called
 // from a BASIC command
 if (!from_command)
 {
  // set the color palette (THIS MUST BE DONE *BEFORE* SETTING A GRAPHICS MODE!)
  // set_palette(desktop_palette);
  set_color_depth(32);

  // set a graphic mode
  if (fullscreen)
   gfxerror=set_gfx_mode(GFX_AUTODETECT,screen_width,screen_height,0,0);
  else
   gfxerror=set_gfx_mode(GFX_AUTODETECT_WINDOWED,screen_width,screen_height,0,0);
  
  if (gfxerror)
  {
#ifdef DEBUG_SCREEN
   pFile = fopen ("errorlog.txt","a");
   fputs ("Function set_gfx_mode failed with GFX_AUTODETECT\n",pFile);
   fputs ("Selected resolution: ",pFile);
   fputc (cfgarray[0]+'0',pFile);
   fputs ("\n",pFile);
   fputs ("Full screen: ",pFile);
   fputc (cfgarray[1]+'0',pFile);
   fputs ("\n-------------\n",pFile);
   fclose (pFile);
#endif
   if (set_gfx_mode(GFX_SAFE,screen_width,screen_height,0,0))
   {
#ifdef DEBUG_SCREEN
    pFile = fopen ("errorlog.txt","a");
    fputs ("Function set_gfx_mode failed with GFX_SAFE\n",pFile);
    fputs ("Selected resolution: ",pFile);
    fputc (cfgarray[0]+'0',pFile);
    fputs ("\n",pFile);
    fputs ("Full screen: ",pFile);
    fputc (cfgarray[1]+'0',pFile);
    fputs ("\n-------------\n",pFile);
    fclose (pFile);
#endif
    set_gfx_mode(GFX_TEXT,0,0,0,0);
    allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
    return 1;
   }
  }
#ifdef DEBUG_SCREEN
  else
  {
   pFile = fopen ("errorlog.txt","a");
   fputs ("Function set_gfx_mode successfully executed with GFX_AUTODETECT\n",pFile);
   fputs ("Selected resolution: ",pFile);
   fputc (cfgarray[0]+'0',pFile);
   fputs ("\n",pFile);
   fputs ("Full screen: ",pFile);
   fputc (cfgarray[1]+'0',pFile);
   fputs ("\n-------------\n",pFile);
   fclose (pFile);
  }
#endif
 }
 
 backcolor=makecol(0,0,240);
 // clear the screen to blue
 clear_to_color(screen,backcolor);
#ifdef DEBUG_SCREEN
 pFile = fopen ("errorlog.txt","a");
 fputs ("Screen cleared to backcolor\n",pFile);
 fclose (pFile);
#endif

 /* you don't need to do this, but on some platforms (eg. Windows) things
 * will be drawn more quickly if you always acquire the screen before
 * trying to draw onto it.
 */
 acquire_screen();
#ifdef DEBUG_SCREEN
 pFile = fopen ("errorlog.txt","a");
 fputs ("Screen acquired\n",pFile);
 fclose (pFile);
#endif

 // create C65 screen
 backcolor=makecol(247,0,0);     CharX=CharY=0; prints((uchar *)"                     "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 backcolor=makecol(247,115,115); Enter();       prints((uchar *)"                  "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 backcolor=makecol(247,247,0);   Enter();       prints((uchar *)"               "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 backcolor=makecol(0,247,0);     Enter();       prints((uchar *)"            "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 backcolor=makecol(148,148,247); Enter();       prints((uchar *)"          "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 backcolor=makecol(247,0,247);   Enter();       prints((uchar *)"        "); forecolor=backcolor; backcolor=makecol(0,0,240); Cout(0xA9);
 
 forecolor=makecol(240,240,240);
 backcolor=makecol(0,0,240);
 CharY=0; Enter();
 CharX=(30<<3)*xzoom; prints((uchar *)"hi65: the high level commodore 65 emulator");
 Enter(); Enter();
 CharX=(34<<3)*xzoom; prints((uchar *)"copyright  2013-"); printn((ulong)YEAR); prints((uchar *)"  ");
 for (i=84; i<88; i++)
  Cout(c65basicerrors[i]);
 Cout(c65basicerrors[23]); CharX+=(1<<3)*xzoom;
 Cout(c65basicerrors[4]); Cout(c65basicerrors[5]);
 Cout(c65basicerrors[462]); Cout(c65basicerrors[463]);
 Cout(c65basicerrors[187]); Cout(c65basicerrors[188]);
 Enter(); Enter();
 CharX=(26<<3)*xzoom; prints((uchar *)" basic 10.0    version "); printn((ulong)VERSION); prints((uchar *)".1    all rights reserved"); Enter(); Enter();
 CharX=0;  prints((uchar *)"default keyboard"); Enter();
 CharX=0;  prints((uchar *)"expansion ram"); Enter();
 CharX=0;  prints((uchar *)"muparser ");
 if (enable_muparser)
  prints((uchar *)"enabled");
 else
  prints((uchar *)"disabled");
 Enter(); Enter();
 // you must always release bitmaps before calling any input functions
 // release_screen();
#ifdef DEBUG_SCREEN
 pFile = fopen ("errorlog.txt","a");
 fputs ("Start screen successfully drawn\n",pFile);
 fclose (pFile);
#endif
 
 return 0;
}

void makeborder(uint bordercolor) // so we can make a border from outside a BASIC 10 program too
{
 // acquire_screen();
 switch (screen_height)
 {
  case 600:
  case 900:
       rectfill(screen,0,screen_border_y,screen_border_x-1,screen_height-screen_border_y,bordercolor);
       rectfill(screen,screen_width-screen_border_x,screen_border_y,screen_width,screen_height-screen_border_y,bordercolor);
  case 480:
       rectfill(screen,0,0,screen_width,screen_border_y,bordercolor);
       rectfill(screen,0,screen_height-screen_border_y,screen_width,screen_height,bordercolor);
       break;
  case 768:
       rectfill(screen,0,screen_border_y,screen_border_x-1,screen_height-screen_border_y,bordercolor);
       rectfill(screen,screen_width-screen_border_x,screen_border_y,screen_width,screen_height-screen_border_y,bordercolor);
       break;
 }
 // release_screen();
}

void alternatescreen()
{
 uchar factor,i;
 
 switch (screentype)
 {
  case 0:
       forecolor=makecol(0,255,0);
       backcolor=makecol(0,0,0);
       chperline=80;
       break;
  case 16:
       forecolor=makecol(187,163,255);
       backcolor=makecol(228,228,228);
       chperline=40;
       break;
  case 20:
       forecolor=makecol(92,203,216);
       backcolor=makecol(255,255,255);
       chperline=20;
       break;
  case 64:
       forecolor=makecol(144,144,240);
       backcolor=makecol(0,0,240);
       chperline=40;
       break;
  case 128:
       forecolor=makecol(179,236,145);
       backcolor=makecol(96,96,96);
       chperline=40;
       break;       
 }
 
 acquire_screen();
 clear_to_color(screen,backcolor);
 makeborder(forecolor);
 
 switch (screen_width)
 {
  case 1280:
  case 1360:
  case 1440:
  case 1600:
       xzoom=yzoom=4;
       factor=4;
       break;
  case 1920:
       xzoom=yzoom=6;
       factor=4;
       break;
  default:
       xzoom=yzoom=2;
       factor=3;
       break;
       
 }
 
 CharX=0; CharY=(1<<factor)<<1;
 
 switch (screentype)
 {
  case 0:
       makeborder(backcolor);
       xzoom>>=1;
       shifted=1;
       prints((uchar *)"*** hi65 - basic v10 ***"); Enter(); Enter();
       prints((uchar *)" (c) "); shifted=0; prints((uchar *)"2013-"); printn((ulong)YEAR); shifted=1; CharX+=(1<<(factor)<<1);
       for (i=84; i<88; i++)
        Cout(c65basicerrors[i]);
       Cout(c65basicerrors[23]); CharX+=(1<<(factor+1));
       Cout(c65basicerrors[4]); Cout(c65basicerrors[5]);
       Cout(c65basicerrors[462]); Cout(c65basicerrors[463]);
       Cout(c65basicerrors[187]); Cout(c65basicerrors[188]);
       Enter();
       break;
  case 16:
       forecolor=makecol(0,0,0);
       shifted=0;
       prints((uchar *)" hi65: high level commodore 65 emulator"); Enter();
       prints((uchar *)" (c) "); prints((uchar *)"2013-"); printn((ulong)YEAR); CharX+=(1<<(factor)<<1);
       for (i=84; i<88; i++)
        Cout(c65basicerrors[i]);
       Cout(c65basicerrors[23]); CharX+=(1<<(factor+1));
       Cout(c65basicerrors[4]); Cout(c65basicerrors[5]);
       Cout(c65basicerrors[462]); Cout(c65basicerrors[463]);
       Cout(c65basicerrors[187]); Cout(c65basicerrors[188]);
       Enter(); Enter();
       break;
  case 20:
       xzoom<<=1;
       forecolor=makecol(59,33,217);
       shifted=0;
       prints((uchar *)"****  hi65 v"); printn((ulong)VERSION); prints((uchar *)" ****"); Enter(); Enter();
       prints((uchar *)"basic v10"); Enter(); Enter();
       break;
  case 64:
       shifted=0;
       prints((uchar *)"       **** hi65 - basic v10 ****"); Enter(); Enter();
       prints((uchar *)" high level commodore 65 emulator  v"); printn((ulong)VERSION); // prints((uchar *)".3");
       Enter(); Enter();
       break;
  case 128:
       shifted=0;
       prints((uchar *)" hi65: high level commodore 65 emulator"); Enter();
       prints((uchar *)"       basic 10.0     version "); printn((ulong)VERSION);  Enter();
       prints((uchar *)"      (c) "); prints((uchar *)"2013-"); printn((ulong)YEAR); CharX+=(1<<(factor)<<1);
       for (i=84; i<88; i++)
        Cout(c65basicerrors[i]);
       Cout(c65basicerrors[23]); CharX+=(1<<(factor+1));
       Cout(c65basicerrors[4]); Cout(c65basicerrors[5]);
       Cout(c65basicerrors[462]); Cout(c65basicerrors[463]);
       Cout(c65basicerrors[187]); Cout(c65basicerrors[188]);
       Enter();
       prints((uchar *)"          all rights reserved"); Enter(); Enter();
 }
 Ready(); 
 release_screen();
}

void flashcursor(void)
{
 if (!tickscapped)
  rectfill(screen,CharX+screen_border_x,CharY+screen_border_y,CharX+(xzoom<<3)+screen_border_x,CharY+(yzoom<<3)+screen_border_y-1,forecolor);
 else if (tickscapped==30)
  rectfill(screen,CharX+screen_border_x,CharY+screen_border_y,CharX+(xzoom<<3)+screen_border_x,CharY+(yzoom<<3)+screen_border_y-1,backcolor);
}

void fastbox(uchar xoffset, uchar yoffset)
{
 fastline(screen,vertex[0][0]+screen_border_x+xoffset,vertex[0][1]+screen_border_y+yoffset,vertex[1][0]+screen_border_x+xoffset,vertex[1][1]+screen_border_y+yoffset,forecolor);
 fastline(screen,vertex[1][0]+screen_border_x+xoffset,vertex[1][1]+screen_border_y+yoffset,vertex[3][0]+screen_border_x+xoffset,vertex[3][1]+screen_border_y+yoffset,forecolor);
 fastline(screen,vertex[3][0]+screen_border_x+xoffset,vertex[3][1]+screen_border_y+yoffset,vertex[2][0]+screen_border_x+xoffset,vertex[2][1]+screen_border_y+yoffset,forecolor);
 fastline(screen,vertex[2][0]+screen_border_x+xoffset,vertex[2][1]+screen_border_y+yoffset,vertex[0][0]+screen_border_x+xoffset,vertex[0][1]+screen_border_y+yoffset,forecolor);
}
