unsigned char dbuff[32000];

/*unsigned char rplane[8000];
unsigned char gplane[8000];
unsigned char bplane[8000];
unsigned char iplane[8000];*/
#define bplane (dbuff+24000)
#define gplane (dbuff+16000)
#define rplane (dbuff+8000)
#define iplane (dbuff)

unsigned dbuff_offset(unsigned x, unsigned y, unsigned char *mask)
{
  *mask = 0x80 >> (x & 7);

  return (y << 5) + (y << 3) + (x >> 3);
}

/*unsigned dbuff_offset_nomask(unsigned x, unsigned y)
{
  return (y << 5) + (y << 3) + (x >> 3);
}*/
#define dbuff_offset_nomask(x, y) ((y << 5) + (y << 3) + (x >> 3))

void put_pixel(unsigned x, unsigned y, unsigned char color)
{
  unsigned char mask;
  unsigned char *ptr = dbuff+dbuff_offset(x, y, &mask);
  unsigned char n;
  static unsigned char nbl;

  if(x >= 320 || y >= 200) return;

  if(nbl++ & 1)
    color >>= 4;

  for(n=4;;)
  {
    if(color & 0x8) *ptr |= mask;
    else *ptr &= ~mask;
    if(!--n) break;
    color <<= 1;
    ptr += 8000;
  }
}

void fill_screen(unsigned char color)
{
  unsigned char *ptr = dbuff;
  unsigned char *ptr2;
  unsigned char color2 = color >> 4;
  unsigned char set_byte;
  unsigned char r;

  memset(ptr, 0, sizeof(dbuff));

  if(color2 != (color & 0xF)) while(1)
  {
    set_byte = 0;
    if(color2 & 0x8)
      set_byte = 0xAA;
    if(color & 0x8)
      set_byte |= 0x55;
    for(ptr2=ptr,r=0;r<200;r++,ptr2+=40)
    {
      memset(ptr2, set_byte, 40);
      set_byte = (set_byte << 1) | (set_byte >> 7);
    }
    color <<= 1;
    color2 <<= 1;
    if((color & 0xF) || (color2 & 0xF))
      ptr += 8000;
    else break;
  }
  else while(1)
  {
    if(color & 0x8)
      memset(ptr, -1, 8000);
    color <<= 1;
    if(color & 0xF)
      ptr += 8000;
    else break;
  }
}

void draw_rectangle(signed x, signed y, unsigned w,
                    unsigned h, unsigned char color)
{
  unsigned o;
  unsigned char mask1, mask2;
  unsigned n,i;
  unsigned char *ptr1, *ptr2, *ptr3;
  unsigned cnt;
  unsigned char color2;
  unsigned char set_byte;
  unsigned char set_mask, set_mask2;

  if(x >= 320 || y >= 200)
    return;

  color2 = color >> 4;

  if(x < 0)
  {
    w += x;
    x = 0;
  }
  if(y < 0)
  {
    h += y;
    y = 0;
  }

  if(x+w > 320) w = 320 - x;
  if(y+h > 200) h = 200 - y;

  ptr1 = ptr3 = dbuff+dbuff_offset(x, y, &mask1);
  ptr2 = dbuff+dbuff_offset(x+w-1, y, &mask2);

  if(mask1 != 0x80)
  {
    for(n=mask1;n>>=1;mask1|=n);
    ptr3++;
  }

  cnt = ptr2 - ptr3;
  if(mask2 != 0x01)
    for(n=mask2;n<<=1;mask2|=n);
  else
    cnt++;

  if(color2 == (color & 0xF))
    for(n=4;;)
    {
      for(i=0,o=0;i<h;i++,o+=40)
      {
        if(color & 0x8)
        {
          *(ptr1+o) |= mask1;
          *(ptr2+o) |= mask2;
          memset(ptr3+o, -1, cnt);
        }
        else
        {
          *(ptr1+o) &= ~mask1;
          *(ptr2+o) &= ~mask2;
          memset(ptr3+o, 0, cnt);
        }
      }
      if(!--n) break;
      color <<= 1;
      ptr1 += 8000;
      ptr2 += 8000;
      ptr3 += 8000;
    }
  else
    for(n=4,set_mask2=0x55;;)
    {
      for(i=0,o=0;i<h;i++,o+=40)
      {
        set_byte = 0;
        *(ptr1+o) &= ~mask1;
        *(ptr2+o) &= ~mask2;
        if(color2 & 0x8)
        {
          set_byte = set_mask2;
          set_mask = mask1 & set_mask2;
          *(ptr1+o) |= set_mask;
          set_mask = mask2 & set_mask2;
          *(ptr2+o) |= set_mask;
        }
        set_mask2 = ~set_mask2;
        if(color & 0x8)
        {
          set_byte |= set_mask2;
          set_mask = mask1 & set_mask2;
          *(ptr1+o) |= set_mask;
          set_mask = mask2 & set_mask2;
          *(ptr2+o) |= set_mask;
        }
        memset(ptr3+o, set_byte, cnt);
      }
      if(!--n) break;
      color <<= 1;
      color2 <<= 1;
      ptr1 += 8000;
      ptr2 += 8000;
      ptr3 += 8000;
    }
}

unsigned char get_pixel(unsigned x, unsigned y)
{
  unsigned char mask;
  unsigned char n;
  unsigned char *ptr = dbuff+dbuff_offset(x, y, &mask);
  unsigned char retval = 0;

  for(n=4;;)
  {
    if(*ptr & mask) retval |= 1;
    if(!--n) break;
    ptr += 8000;
    retval <<= 1;
  }

  return retval;
}

void get_scrarea(unsigned x, unsigned y, unsigned width, unsigned height, unsigned char *trg)
{
  unsigned char *ptr = dbuff+dbuff_offset_nomask(x, y);
  unsigned char *pptr;
  unsigned n,h;
  unsigned copy_count = (width>>3)+1;

  for(n=4;n--;ptr+=8000)
  {
    pptr = ptr;
    for(h=height;h--;)
    {
      memcpy(trg, pptr, copy_count);
      pptr += 40;
      trg += copy_count;
    }
  }
}

void set_scrarea(unsigned x, unsigned y, unsigned width, unsigned height, unsigned char *src)
{
  unsigned char *ptr = dbuff+dbuff_offset_nomask(x, y);
  unsigned char *pptr;
  unsigned n,h;
  unsigned copy_count = (width>>3)+1;

  for(n=4;n--;ptr+=8000)
  {
    pptr = ptr;
    for(h=height;h--;)
    {
      memcpy(pptr, src, copy_count);
      pptr += 40;
      src += copy_count;
    }
  }
}

void darken_screen(void)
{
  unsigned x, y;
  unsigned char color;

  for(y=0;y<200;y++)
    for(x=0;x<320;x++)
    {
      if((color = get_pixel(x, y)) & 0x8)
        put_pixel(x, y, color & 7);
      else
        put_pixel(x, y, 0);
    }
}
