//**************************************************************************//
// Das hier ist eine Include-Datei mit Graphikroutinen                      //
// ----------------------------------------------------                     //
// von Stephan Meiáner                                                      //
// ab 25. M„rz 1996                                                         //
//**************************************************************************//
#define 320x200                         1
#define 640x480                         2
#define byte                            BYTE
#define word                            WORD
#define setpix(x,y,c,r)                 Screen[(y)*r+(x)]=(c)
#define vsetpix(x,y,c,r)                VScreen[((y)*r)+(x)]=(c)
#define getpix(x,y,r)                   Screen[(y)*r+(x)]
#define vgetpix(x,y,r)                  VScreen[((y)*r)+(x)]
#define out_Sequencer(index,value)      { outp(0x3c4,index); outp(0x3c5,value); }
#define in_Sequencer(index,data)        { outp(0x3c4,index); data=inp(0x3c5); }

typedef unsigned char BYTE;
typedef unsigned WORD;

char *Screen = (char *)0xa0000;
char *VScreen;
int res, res_x, res_y;
int SPIEL_LANG, SPIEL_BREIT;
int Mlinks, Mrechts, Moben, Munten;
/****************************************************************************/
/* Initialisiert den Mode 13h.                                              */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void init320x200( void )
{
   union REGS regs;

   regs.x.ax = 0x0013;      
   int386( 0x10, &regs, &regs );
   VScreen = realloc(VScreen, 320*200);
   res   = 320x200;
   res_x = 320;
   res_y = 200;

   SPIEL_LANG = 9; SPIEL_BREIT = 13;
   Mlinks = 0; Mrechts = 260; Moben = -1; Munten = 180;
}

/****************************************************************************/
/* Initialisiert den Mode 640x480.                                          */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void init640x480 ( void )
{
   union REGS regs;

   regs.x.ax = 0x4F02;    
   regs.x.bx = 0x0101;
   int386( 0x10, &regs, &regs );
   VScreen = realloc(VScreen, 330000);
   res   = 640x480;
   res_x = 640;
   res_y = 480;

   SPIEL_LANG = 22; SPIEL_BREIT = 26;
   Mlinks = 0; Mrechts = 520; Moben = -1; Munten = 420;
}

/****************************************************************************/
/* Initialisiert den Textmodus.                                             */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void textmodus( void )
{
   union REGS regs;

   regs.x.ax = 0x0003;               /* wieder in Textmodus zurckschalten */
   int386( 0x10, &regs, &regs );
}

/****************************************************************************/
/* Kopiert den virtuellen auf den "richtigen" Bildschirm.                   */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void cpy2screen( void )
{
   union REGS regs;

   if ( res == 320*200 ) memcpy(Screen, VScreen, 64000);
   else
   {
     regs.x.ax = 0x4F05; regs.x.bx = 0x0000; regs.x.dx = 0x0000;
     int386( 0x10, &regs, &regs );
     memcpy(Screen, VScreen, 65535);

     regs.x.ax = 0x4F05; regs.x.bx = 0x0000; regs.x.dx = 0x0001;
     int386( 0x10, &regs, &regs );
     memcpy(Screen, &VScreen[65536], 65535);

     regs.x.ax = 0x4F05; regs.x.bx = 0x0000; regs.x.dx = 0x0002;
     int386( 0x10, &regs, &regs );
     memcpy(Screen, &VScreen[131072], 65535); 

     regs.x.ax = 0x4F05; regs.x.bx = 0x0000; regs.x.dx = 0x0003;
     int386( 0x10, &regs, &regs );
     memcpy(Screen, &VScreen[196608], 65535); 

     regs.x.ax = 0x4F05; regs.x.bx = 0x0000; regs.x.dx = 0x0004;
     int386( 0x10, &regs, &regs );
     memcpy(Screen, &VScreen[262144], 65535); 
   }

}

/****************************************************************************/
/* Wartet auf den Kathoden-Rcklauf                                         */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void wait_retrace(void)
{
  while ((inp(0x03da) & 1) != 0);
  while ((inp(0x03da) & 1) == 0); 
}

/****************************************************************************/
/* Wartet auf den vertikalen Kathoden-Rcklauf                              */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void wait_vretrace(void)
{
  while ((inp(0x03da) & 8) != 0);
  while ((inp(0x03da) & 8) == 0);
}

/****************************************************************************/
/* Setzt die Farbe des Bildschirmrahmens.                                   */
/* ------------------------------------------------------------------------ */
/* Parameter: Farbe des Rahmens.                                            */
/****************************************************************************/
void Set_Overscan_Color( BYTE color )
{
  wait_retrace();
  outp(0x3c0,0x11);  // Index fr Overscan-Register schreiben
  outp(0x3c0,color); // Farbe setzen
  outp(0x3c0,0x20);  // Bit 5 im Indexregister l”schen
}

/****************************************************************************/
/* Schaltet den Bildschirmaufbau vorbergehend aus.                         */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void Screen_Off(void)
{
  BYTE old_clock;

  in_Sequencer(1,old_clock);
  out_Sequencer(1,old_clock | 0x20);
}

/****************************************************************************/
/* Schaltet den Bildschirmaufbau wieder ein.                                */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void Screen_On(void)
{
  BYTE old_clock;

  in_Sequencer(1,old_clock);
  out_Sequencer(1,old_clock & 0xDF);
}

/****************************************************************************/
/* Setzt die bergebene Palette.                                            */
/* ------------------------------------------------------------------------ */
/* Parameter: Zeiger auf die Palette.                                       */
/****************************************************************************/
void SetPalette(char *Palette)
{
  short int i;
  char far *p;

  for (i=0; i<768; i++) Palette[i] = Palette[i] >> 2;
  p = Palette;

  outp(0x3c6, 0xff);
  for (i=0; i<=255; i++)
  {
    outp(0x3c8, i);
    outp(0x3c9, *p++);
    outp(0x3c9, *p++);
    outp(0x3c9, *p++);
  }

return;
}

void Set_Palette(WORD start,WORD end,BYTE *palette)
{
  WORD i;
  outp(0x03c8,start);
  start*=3;
  end++; end*=3;
  for (i=start;i<end;i++) outp(0x03c9,palette[i]);
}


/****************************************************************************/
/* Ermittelt die gerade gesetzte Palette.                                   */
/* ------------------------------------------------------------------------ */
/* Parameter: Zeiger auf die Palette.                                       */
/****************************************************************************/
void GetPalette ( BYTE *Palette )
{
   WORD i;

   outp(0x03c7, 0);
   for (i=0; i<768; i++) Palette[i] = inp(0x03c9);
}

/****************************************************************************/
/* L”scht die gerade aktuelle Palette.                                      */
/* ------------------------------------------------------------------------ */
/* keine Parameter                                                          */
/****************************************************************************/
void ClearPalette ( void )
{
  BYTE palette[786] = {0};
  SetPalette(palette);
}

/****************************************************************************/
/* Wird zum Ein- und Ausblenden des Bildschirms gebraucht.                  */
/* ------------------------------------------------------------------------ */
/* Parameter: Anfang, Ende und die Palette die ver„nder werden soll, sowie  */
/*            die Intensit„t.                                               */    
/****************************************************************************/
void Set_Palette2(word start,word end,byte *palette,byte blend)
{
  WORD i;

  outp(0x03c8,start);
  start*=3; end++; end*=3;
  for (i=start;i<=end;i++) outp(0x03c9, (palette[i]*blend >> 7));
}

/****************************************************************************/
/* Blendet den Bildschirm aus.                                              */
/* ------------------------------------------------------------------------ */
/* keine Parameter.                                                         */
/****************************************************************************/
void fade_out(void)
{
  BYTE PALETTE[768];
  int blend_count;

  GetPalette(PALETTE);
  for (blend_count=128;blend_count>=0;blend_count-=2)
  {
     wait_vretrace();
     Set_Palette2(0,255,PALETTE,blend_count);
  }
}

/****************************************************************************/
/* Blendet den Bildschirm ein.                                              */
/* ------------------------------------------------------------------------ */
/* keine Parameter.                                                         */
/****************************************************************************/
void fade_in( BYTE PALETTE[768] )
{
  int blend_count;

  for (blend_count=0;blend_count<32;blend_count++)
  {
    wait_vretrace();
    Set_Palette2(0,255,PALETTE,blend_count);
  }
}

/****************************************************************************/
/* Blendet den Bildschirm ab einem best. Bereich ein.                       */
/* ------------------------------------------------------------------------ */
/* Parameter: Anfang und Ende des Einblendbereiches                         */
/****************************************************************************/
void set_fade_in( BYTE PALETTE[768], int start, int end )
{
  int blend_count;

  for (blend_count=0;blend_count<30;blend_count++)
  {
    wait_vretrace(); 
    Set_Palette2(start,end,PALETTE,blend_count);
  }
}

/****************************************************************************/
/* Blendet den Bildschirm aus.                                              */
/* ------------------------------------------------------------------------ */
/* Parameter: Anfang und Ende des Einblendbereiches                         */
/****************************************************************************/
void set_fade_out( int start, int end )
{
  BYTE PALETTE[768];
  int blend_count;

  GetPalette(PALETTE);
  for (blend_count=128;blend_count>=0;blend_count-=2)
  {
     wait_vretrace();
     Set_Palette2(start,end,PALETTE,blend_count);
  }
}

/****************************************************************************/
/* Blendet den Bildschirm aus.                                              */
/* ------------------------------------------------------------------------ */
/* Parameter: Anfang und Ende des Einblendbereiches, und wie dunkel.        */
/****************************************************************************/
void set_pal_out( int start, int end, int weite )
{
  BYTE PALETTE[768];
  int blend_count;

  GetPalette(PALETTE);
  wait_vretrace();
  Set_Palette2(start,end,PALETTE,weite);
}

void rotate_pal ( WORD count, WORD start, WORD end, BYTE *pal, BYTE start_col )
{
  WORD i;

  outp(0x03c8, start_col);
  start*=3;
  end++; end*=3;
  count*=3;
  for ( i=count; i<end; i++ ) outp(0x03c9, pal[i]);
  for ( i=start; i<=count; i++ ) outp(0x03c9, pal[i]);
}

void clr_screen ( void )
{
  memset(Screen, 255, 64000);
}
void clr_vscreen ( void )
{
  memset(VScreen, 255, 64000);
}
