/* Screen display routines              */
/* written by Günther Röhrich           */
/* this source is Public Domain         */

/* this works only with OS 3.0 or higher */

/* last change: 1-Feb-1995 */

#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <graphics/modeid.h>


#ifndef __GNUC__
#include <pragmas/intuition_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#else
#include <inline/graphics.h>  
#include <inline/intuition.h> 
#include <inline/exec.h>
#endif

#define HAM8 1
#define ERROR_INTUITION 2
#define ERROR_GRAPHICS 3

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
extern struct Library *IconBase;

struct WBFlags
{
 int scale;
 short VGAenable;
 short SUPER72enable;
 short SMRenable;
 short GrayEnable;
 short NoSmooth;
 short DCTFast;
 short ScaleFit;
};

extern struct WBFlags WBFlags;
extern short DoNotWait;
extern short finish;

extern ULONG SMR_DisplayID;
extern ULONG *ScreenColorTable;
extern ULONG ScaleFitDisplayID;
struct Screen *my_tempscreen  = NULL;
struct Screen *my_screen[2] = {NULL, NULL};
struct Window *my_tempwindow =  NULL;
struct Window *my_window[2] = {NULL, NULL};
struct RastPort temprp; /* a copy of the screen's RastPort */
int Drow; 

struct TagItem MyScreenTags[] = {

{ SA_Width,     (ULONG)0 },
{ SA_Height,    (ULONG)0 },
{ SA_Depth,     (ULONG)0 },
{ SA_DisplayID, (ULONG)0 },
{ SA_Behind,    (ULONG)FALSE },
{ SA_Colors32,  NULL},
{ SA_Parent,    NULL },
{ SA_Type,      (ULONG)CUSTOMSCREEN },
{ SA_Quiet,     (ULONG)TRUE },
{ SA_AutoScroll,(ULONG)TRUE },
{ SA_Overscan,  (ULONG)OSCAN_STANDARD },
{ TAG_DONE,     (ULONG)TRUE }  };

struct TagItem MyWindowTags[] = {

{ WA_Width,        (ULONG)0 },
{ WA_Height,       (ULONG)0 },
{ WA_CustomScreen, NULL },
{ WA_Activate,     (ULONG)TRUE },
{ WA_Left,         (ULONG)0 },
{ WA_Top,          (ULONG)0 },
{ WA_NoCareRefresh,(ULONG)TRUE },
{ WA_Borderless,   (ULONG)TRUE },
{ WA_Backdrop,     (ULONG)TRUE },
{ WA_RMBTrap,      (ULONG)TRUE }, /* disable screen menu drawing */
{ WA_IDCMP,        (ULONG)IDCMP_MOUSEBUTTONS | IDCMP_VANILLAKEY },
{ WA_BusyPointer,  (ULONG)TRUE }, /* V39 only! */
{ TAG_DONE,        (ULONG)TRUE } };

void CloseDisplay(void);
void FlipScreen(void);
void FinalWait(void);

/* Initialize the display, colors will be set later */
/* if there is a screen open it in the background as my_screen[1] */


int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes)
{
  ULONG Depth, DisplayID;
  ULONG NoSUPER72, i=0;

  Drow=0;


  if(!IntuitionBase)
  {
    if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary((UBYTE *)"intuition.library", 39)))
    {
     printf("Could not open intuition.library V39 or higher.\n"); 
     return 0;
    }
  }

  if(!GfxBase)
  {
    if(!(GfxBase = (struct GfxBase *)OpenLibrary((UBYTE *)"graphics.library",39)))
    {
      printf("Could not open graphics.library V39 or higher.\n");
      return 0;
    }
  }

  /* If we already have two screens we must close one */

  if(my_screen[0] && my_screen[1])
  {
    FinalWait();
    if(finish) return 0;
    FlipScreen();
  }

  if(WBFlags.SMRenable)
  {
    DisplayID = SMR_DisplayID;
  }
  else
  {
    /* Calculate a DisplayID */
    /* this should be done better... */

    /* check if SUPER72 mode is available */

    NoSUPER72 = ModeNotAvailable(SUPER72_MONITOR_ID | SUPERHAMLACE_KEY);

    if(WBFlags.VGAenable)
    {
      if(Mode == HAM8)
      {
        if(cols > 780 && !NoSUPER72 && WBFlags.SUPER72enable) DisplayID = SUPER72_MONITOR_ID | SUPERHAMLACE_KEY;
        else
        if(cols > 370 || rows > 260)
          DisplayID = VGAPRODUCTHAM_KEY;
        else
          DisplayID = VGALORESHAMDBL_KEY;
      }
      else
      {
        if(cols > 780 && !NoSUPER72 && WBFlags.SUPER72enable) DisplayID = SUPER72_MONITOR_ID | SUPERLACE_KEY;
        else
        if(cols > 370 || rows >260) 
          DisplayID = VGAPRODUCT_KEY;
        else
          DisplayID = VGALORESDBL_KEY;        
      }
    }
    else
    {  
      if(Mode == HAM8)
      {
        if(cols > 370 || rows > 260)
          DisplayID = HIRESHAMLACE_KEY;
        else
          DisplayID = HAM_KEY;
      }
      else
      {
        if(cols > 370 || rows >260) 
          DisplayID = HIRESLACE_KEY;
        else
          DisplayID = LORES_KEY; 
      }   
    }

    if(ScaleFitDisplayID)
    {
      DisplayID = ScaleFitDisplayID;
      /* printf("ScaleFitDisplayID used.\n"); */
    }
  }

  if(Mode == HAM8) Depth = 8;
    else Depth = NumPlanes;

 MyScreenTags[0].ti_Data = (ULONG)cols;
 MyScreenTags[1].ti_Data = (ULONG)rows;
 MyScreenTags[2].ti_Data = (ULONG)Depth;
 MyScreenTags[3].ti_Data = (ULONG)DisplayID;
 MyScreenTags[5].ti_Data = (ULONG)((void *)ScreenColorTable);

 MyWindowTags[0].ti_Data = (ULONG)cols;
 MyWindowTags[1].ti_Data = (ULONG)rows;

  while(1)
  {
    if(my_tempscreen == NULL)
    {
      if(my_screen[0] == NULL)
      {
        MyScreenTags[4].ti_Data = (ULONG)FALSE;
        MyScreenTags[6].ti_Tag = TAG_IGNORE;
        my_tempscreen = OpenScreenTagList(NULL, (struct TagItem *)&MyScreenTags);
      }
      else
      {
        MyScreenTags[4].ti_Data = (ULONG)TRUE;
        MyScreenTags[6].ti_Tag = SA_Parent;
        MyScreenTags[6].ti_Data = (ULONG)((void *)my_screen[0]);
        my_tempscreen = OpenScreenTagList(NULL, (struct TagItem *)&MyScreenTags);
      }
    }

    if(my_tempscreen == NULL)
    {
      /* do we already have a screen ? */
      if(my_screen[0])
      {
        printf("Could not open background screen. (out of memory)\n");
        if(!DoNotWait) FinalWait();
        FlipScreen();
        if(finish) return 0;
        continue;
      }
      else return 0;
    }
    
    /* open a dummy window to allow autoscroll feature      */
  
    if(my_tempwindow == NULL && my_tempscreen)
    {
      MyWindowTags[2].ti_Data = (ULONG)((void *)my_tempscreen);
      if(my_screen[0] == NULL)
      {
        MyWindowTags[3].ti_Data = (ULONG)TRUE;
        my_tempwindow = OpenWindowTagList(NULL, (struct TagItem *)&MyWindowTags);
      }
      else
      {
        MyWindowTags[3].ti_Data = (ULONG)FALSE;
        my_tempwindow = OpenWindowTagList(NULL, (struct TagItem *)&MyWindowTags);
      }
    }

    if(my_tempwindow == NULL)
    {
      if(my_tempscreen)
      {
        CloseScreen(my_tempscreen);
        my_tempscreen = NULL;
      }

      /* do we already have a screen ? */
      if(my_screen[0])
      {
        printf("Could not open window on background screen. (out of memory)\n");
        /* wait for a mouse button press and close it */
        if(!DoNotWait) FinalWait();
        FlipScreen();
        if(finish) return 0;
        continue;
      }
      else return 0;
    }

    /* initialize temprp for use with WritePixelLine8() */

    if(temprp.BitMap) FreeBitMap(temprp.BitMap);
    CopyMem(&my_tempscreen->RastPort, &temprp, sizeof(struct RastPort));
    temprp.Layer = NULL;
    /* V39 function */
    temprp.BitMap = AllocBitMap(cols, 1, my_tempscreen->RastPort.BitMap->Depth, 0, my_tempscreen->RastPort.BitMap);

    if(temprp.BitMap == NULL)
    {
      if(my_tempwindow)
      {
        CloseWindow(my_tempwindow);
        my_tempwindow = NULL;
      }
      if(my_tempscreen)
      {
        CloseScreen(my_tempscreen);
        my_tempscreen = NULL;
      }

      /* do we already have a screen ? */
      if(my_screen[0])
      {
        printf("Could not open temporary line bitmap (out of memory)\n");
        /* wait for a mouse button press and close it */
        if(!DoNotWait) FinalWait();
        FlipScreen();
        if(finish) return 0;
        continue;
      }
      else return 0;
    }
  break;
  }
  if(my_screen[0]) i=1;
  my_screen[i] = my_tempscreen;
  my_window[i] = my_tempwindow;
  my_tempscreen = NULL;
  my_tempwindow = NULL;  

  if(DoNotWait && my_screen[1]) FlipScreen();

  return 1; /* success */  
}



/* Close the display */

void CloseDisplay(void)
{
  int i=0;
  if(my_screen[1] && !finish)
  {
    FlipScreen();
    FinalWait();
  }

  
  if(my_screen[1]) i=1;

  if(temprp.BitMap)
  {
    /* V39 function */
    FreeBitMap(temprp.BitMap);
    temprp.BitMap = NULL;
  }
  for(i=0; i < 2; i++)
  {
    if(my_screen[i]) ScreenToBack(my_screen[i]);
    if(my_window[i])
    {
      CloseWindow(my_window[i]);
      my_window[i] = NULL;
    }
    if(my_screen[i])
    {
      CloseScreen(my_screen[i]);
      my_screen[i] = NULL;
    }
  }
  if(IntuitionBase)
  {
   CloseLibrary((struct Library *)IntuitionBase);
   IntuitionBase = NULL;
  }
  if(GfxBase)
  {
    CloseLibrary((struct Library *)GfxBase);
    GfxBase = NULL;
  }
  if(IconBase)
  {
    CloseLibrary(IconBase);
    IconBase=NULL;
  }
}


/* display a line of chunky pixel graphics... */


void DisplayRow(char *array, int cols)
{
  int i=0;
  if(my_screen[1]) i=1;
  if(my_screen[i])
    WritePixelLine8(&my_screen[i]->RastPort, 0, Drow++, cols, (UBYTE *)array, &temprp);
}


/* check for a right mouse button press (or Esc press) */

int CheckButton(void)
{
  struct IntuiMessage *msg;
  int Button = 0;

  if(my_window[0])
  {
    while(msg = (struct IntuiMessage *)GetMsg(my_window[0]->UserPort))
    {
      if(msg->Class == IDCMP_MOUSEBUTTONS)
        if(msg->Code == MENUDOWN)
          Button = 1; 
      if(msg->Class == IDCMP_VANILLAKEY)
        if(msg->Code == 27)  /* Esc */
        {
          Button = 2;
          finish = 1;
        }
      ReplyMsg((struct Message *)msg);
      if(Button) break;
    }
  }
  if(Button && my_screen[1] && !finish)
  {
    FlipScreen();
    Button = 0;
  }
  return Button;
}
       
/* final wait after the picture is finished */

void FinalWait(void)
{
  struct IntuiMessage *msg;
  int Button = 0;
  struct TagItem WinPointerSet[] = { {WA_Pointer, NULL}, {TAG_DONE, NULL} };

  /* always wait for my_screen[0] */


  /* set the normal pointer */
  /* V39 function */

  if(!my_window[0]) return; 

  /* SetWindowPointer(my_window[0], WA_Pointer, NULL, TAG_DONE); */
  SetWindowPointerA(my_window[0], WinPointerSet);
  
  if(my_window[0])
  {
    while(!Button)
    {
      Wait(1L<<my_window[0]->UserPort->mp_SigBit);
      while(msg = (struct IntuiMessage *)GetMsg(my_window[0]->UserPort))
      {
        if(msg->Class == IDCMP_MOUSEBUTTONS)
          if(msg->Code == MENUDOWN) Button = 1;
        if(msg->Class == IDCMP_VANILLAKEY)
          if(msg->Code == 27) /* Esc */
          {
            Button = 2;
            finish = 1;
          }
        ReplyMsg((struct Message *)msg);
        if(Button) break;
      }
    }
  }
}

void FlipScreen(void)
{
 if(my_screen[0] && my_screen[1])
 {
  ScreenDepth(my_screen[1], SDEPTH_TOFRONT | SDEPTH_INFAMILY, NULL);
  if(my_window[1]) ActivateWindow(my_window[1]);
 }
 else if(my_screen[0]) ScreenToBack(my_screen[0]);
 

 if(my_window[0])
 {
   CloseWindow(my_window[0]);
   my_window[0] = NULL;
 }

 if(my_screen[0])
 { 
   CloseScreen(my_screen[0]);
   my_screen[0] = NULL;
 }


 if(my_screen[1])
 {
   my_screen[0] = my_screen[1];
   my_screen[1] = NULL;
   my_window[0] = my_window[1];
   my_window[1] = NULL;
 }
}
