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

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

#include <stdio.h>

#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


struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
extern int VGAenable; /* indicates if user wants to have VGA mode */
extern int SUPER72enable; /* indicates if user wants to have SUPER72 mode */
static void error_exit(const char *msgtext);
struct Screen *my_screen = NULL;
struct Window *my_window = NULL;
struct RastPort temprp; /* a copy of the screen's RastPort */
int Drow = 0; 
extern ULONG *ScreenColorTable;


struct TagItem MyScreenTags[] = {

{ SA_Width,     (ULONG)0 },
{ SA_Height,    (ULONG)0 },
{ SA_Depth,     (ULONG)0 },
{ SA_DisplayID, (ULONG)0 },
{ SA_Colors32,  (ULONG)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, (ULONG)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);

/* Initialize the display, colors will be set later */

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

  if(!(IntuitionBase = OpenLibrary((UBYTE *)"intuition.library", 39)))
   error_exit("Can't open intuition.library V39 or higher");

  if(!(GfxBase = OpenLibrary((UBYTE *)"graphics.library",39)))
   error_exit("Can't open graphics.library V39 or higher");

  
  /* Calculate a DisplayID */
  /* this should be done better... */

  /* check if SUPER72 mode is available */

  NoSUPER72 = ModeNotAvailable(SUPER72_MONITOR_ID | SUPERHAMLACE_KEY);


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

  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[4].ti_Data = (ULONG)((void *)ScreenColorTable);

  MyWindowTags[0].ti_Data = (ULONG)cols;
  MyWindowTags[1].ti_Data = (ULONG)rows;
  
  my_screen = OpenScreenTagList(NULL, (struct TagItem *)&MyScreenTags);

  if(my_screen == NULL)  return 0;
    
  /* open a dummy window to allow autoscroll feature      */
  
  MyWindowTags[2].ti_Data = (ULONG)((void *)my_screen);
  my_window = OpenWindowTagList(NULL, (struct TagItem *)&MyWindowTags);

  if(my_window == NULL) return 0;

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

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

  if(temprp.BitMap == NULL) return 0;

  /* set pens and drawing modes */

  if(Depth == 8)
  {
    SetAPen(&my_screen->RastPort, 255); 
    SetDrMd(&my_screen->RastPort, JAM1);
  }


  return 1; /* success */  
}


/* Close the display */

void CloseDisplay(void)
{
  if(my_screen) ScreenToBack(my_screen);

  if(temprp.BitMap)
  {
    /* V39 function */
    FreeBitMap(temprp.BitMap);
    temprp.BitMap = NULL;
  }
  if(my_window)
  {
    CloseWindow(my_window);
    my_window = NULL;
  }
  if(my_screen)
  {
    CloseScreen(my_screen);
    my_screen = NULL;
  }
  if(IntuitionBase)
  {
   CloseLibrary(IntuitionBase);
   IntuitionBase = NULL;
  }
  if(GfxBase)
  {
    CloseLibrary(GfxBase);
    GfxBase = NULL;
  }
}


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


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

void DisplayRowPos(char *array, int cols, int xpos, int ypos)
{
  if(my_screen)
    WritePixelLine8(&my_screen->RastPort, (ULONG)xpos, (ULONG)ypos, cols, array, &temprp);
}


void DisplayNrGray(int nr, int xpos, int ypos)
{
  if(my_screen)
  {
    char String[10];
    sprintf(String, "%d", nr);
    Move(&my_screen->RastPort, (SHORT)xpos, (SHORT)ypos);
    Text(&my_screen->RastPort, String, strlen(String));
  }
} 

/* check for a right mouse button press */

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

  if(my_window)
  {
    while(msg = (struct IntuiMessage *)GetMsg(my_window->UserPort))
    {
      if(msg->Class == IDCMP_MOUSEBUTTONS)
        if(msg->Code == MENUDOWN)
          Button = 1; 
      ReplyMsg((struct Message *)msg);
      if(Button) break;
    }
  }
  return Button;
}
       
/* final wait after the picture is finished */

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

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

  /* SetWindowPointer(my_window, WA_Pointer, NULL, TAG_DONE); */
  SetWindowPointerA(my_window, WinPointerSet);
  
  if(my_window)
  {
    while(!Button)
    {
      Wait(1L<<my_window->UserPort->mp_SigBit);
      while(msg = (struct IntuiMessage *)GetMsg(my_window->UserPort))
      {
        if(msg->Class == IDCMP_MOUSEBUTTONS)
          if(msg->Code == MENUDOWN) Button = 1; 
        ReplyMsg((struct Message *)msg);
        if(Button) break;
      }
    }
  }
}
      
static void error_exit(const char *msgtext)
{
 printf("%s", msgtext);
 CloseDisplay();
 exit(10);
}
