/* 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 */

#pragma regcall(newWPL8(a0,d0,d1,d2,a2))

#define INTUI_V36_NAMES_ONLY

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

#define __NOLIBBASE__
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/graphics.h>

#ifdef __GNUC__
extern __inline void
newWPL8(struct RastPort *rp, unsigned long xstart, unsigned long ystart,
        unsigned long width, UBYTE *array)
{
  register struct RastPort *a0 __asm("a0") = rp;
  register unsigned long d0 __asm("d0") = xstart;
  register unsigned long d1 __asm("d1") = ystart;
  register unsigned long d2 __asm("d2") = width;
  register UBYTE *a2 __asm("a2") = array;
  __asm __volatile ("jsr _newWPL8"
  : /* no output */
  : "r" (a0), "r" (d0), "r" (d1), "r" (d2), "r" (a2)
  : "a0","a1","a2","d0","d1","d2", "memory");
}
#endif


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

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

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

extern ULONG SMR_DisplayID;
extern ULONG *ScreenColorTable;
extern ULONG ScaleFitDisplayID;

/* for newWPL8() */
PLANEPTR PlanePos[8];
UBYTE    *linebuf = NULL;

struct BitMap *my_tempbitmap = NULL;
struct BitMap *my_bitmap[2] = {NULL,NULL};
struct Screen *my_tempscreen  = NULL;
struct Screen *my_screen[2] = {NULL, NULL};
struct Window *my_tempwindow =  NULL;
struct Window *my_window[2] = {NULL, NULL};
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_BitMap,    NULL},
{ SA_Type,      (ULONG)CUSTOMSCREEN|CUSTOMBITMAP },
{ 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_tempbitmap == NULL)
    {
      my_tempbitmap = AllocBitMap(((cols+31)>>5)<<5,rows,Depth,BMF_CLEAR|BMF_DISPLAYABLE,NULL);
      MyScreenTags[7].ti_Data = (ULONG)my_tempbitmap;
    }

    if(my_tempbitmap == 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;
    }


    if(my_tempscreen == NULL && my_tempbitmap)
    {
      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 && my_tempbitmap)
    {
      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;
      }

      if(my_tempbitmap)
      {
        FreeBitMap(my_tempbitmap);
        my_tempbitmap = 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;
    }

    /* Allocate line buffer for newWPL8 */

    if(linebuf) FreeVec(linebuf);
    linebuf = AllocVec((ULONG)cols+32L, 0);
    if(linebuf == NULL)
    {
      if(my_tempwindow)
      {
        CloseWindow(my_tempwindow);
        my_tempwindow = NULL;
      }
      if(my_tempscreen)
      {
        CloseScreen(my_tempscreen);
        my_tempscreen = NULL;
      }

      if(my_tempbitmap)
      {
        FreeBitMap(my_tempbitmap);
        my_tempbitmap = NULL;
      }
      
      if(my_screen[0])
      {
        printf("Could not allocate line buffer (out of memory)\n");
        if(!DoNotWait) FinalWait();
        FlipScreen();
        if(finish) return 0;
        continue;
      }
      else return 0;
    }
    break;
  }

  if(my_screen[0]) i=1;
  my_bitmap[i] = my_tempbitmap;
  my_screen[i] = my_tempscreen;
  my_window[i] = my_tempwindow;
  my_tempbitmap = NULL;
  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(linebuf)
  {
    FreeVec(linebuf);
    linebuf = 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(my_bitmap[i])
    {
      FreeBitMap(my_bitmap[i]);
      my_bitmap[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])
  {
   int j;
   struct RastPort *MyRastPtr;
   MyRastPtr = &my_screen[i]->RastPort;
   for(j=0; j<8; j++)
     PlanePos[j]=MyRastPtr->BitMap->Planes[j] + MyRastPtr->BitMap->BytesPerRow*Drow;
   newWPL8(MyRastPtr, 0, Drow, cols, (UBYTE *)array);
   Drow++;
   /*  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_bitmap[0])
 {
   FreeBitMap(my_bitmap[0]);
   my_bitmap[0] = NULL;
 }

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