/* Screen and window functions.  Creating and Closing them.
 * Yes there are several functions in here that aren't documented.
 * If you think you need them, go right ahead and use 'em.  I felt
 * it would be best to keep everything encapsulated the way it is.
 *
 * Dominic Giampaolo.
 */

#include "ezlib.h"

extern struct GfxBase *GfxBase;
extern struct IntuitionBase *IntuitionBase;
extern int openlibs();

void *AllocMem();
void *AllocRaster();

struct BitMap *getbitmap();

/* this function will open a custom screen for
 * you.  Simply tell it the type (HIRES, LACE, etc) and
 * the depth.  The rest is taken care of.
 */

 /* structure will be mostly filled in later */
 static struct NewScreen ez_DefaultScreen =
  {
   0L, 0L,		     /* left edge, top edge   */
   320L, 200L,		     /* width,	   height     */
   1L,			     /* depth		      */
   0L, 1L,		     /* detailpen, blockpen   */
   0L,			     /* ViewModes,	      */
   CUSTOMSCREEN|SCREENQUIET, /* type,		      */
   NULL,		     /* Font,		      */
   NULL,		     /* title,		      */
   NULL, NULL		     /* Gadgets, Bitmap       */
  };


struct Screen *makescreen(modes, depth)
 register int modes;
 register int depth;
{
 struct Screen *OpenScreen(), *temp_ptr;
 struct NewScreen NewScreen;

 /* some sanity checking - short and fast */
 if(GfxBase == NULL || IntuitionBase == NULL)
  if ( openlibs(GFX | INTUITION) == NULL)
    return NULL;

 NewScreen = ez_DefaultScreen;		 /* copy in the default struct */

 NewScreen.ViewModes = modes;	     /* assume modes value is o.k. */

 if (modes & HIRES)
   NewScreen.Width = 640;
 if (modes & LACE)
   NewScreen.Height = (SHORT)( 2 * GfxBase->NormalDisplayRows );
 else
   NewScreen.Height = (SHORT)GfxBase->NormalDisplayRows;

 /* check depth field to make sure it agrees with resolution type */
 if (depth > 4 && (modes & HIRES))
   depth = 4;

 if (depth <= 0)
   depth = 1;

 if (modes & HAM)                          /* make sure we have ok vals */
   { depth = 6; NewScreen.Width = 320; }

 if (modes & EXTRA_HALFBRITE)              /* give valid values */
   { depth = 6; NewScreen.Width = 320; }

 /* make sure no foolishness here */
 if (depth > 6)
   depth = 6;

 NewScreen.Depth = depth;		   /* o.k. to do this now */

 /* now see if we have to allocate bitmap stuff */
 if (depth > 2) {
   NewScreen.CustomBitMap = (struct BitMap *)getbitmap( depth, NewScreen.Width, NewScreen.Height );
   if (NewScreen.CustomBitMap == NULL)
     return NULL;
   NewScreen.Type |= CUSTOMBITMAP;
 }

 temp_ptr = OpenScreen(&NewScreen);

 /* we shove the bitmap ptr into the user data field so we can free it
  * properly later on.	READ: don't use the ExtData field of your screen,
  * or if you do, save it first and then restore it before calling
  * killscreen()!
  */

 if (temp_ptr != NULL && depth > 2)
   temp_ptr->ExtData = (UBYTE *)NewScreen.CustomBitMap;

 return temp_ptr;
}     /*  end of makescreen()  */


struct BitMap *getbitmap(depth, width, height)
 int depth, width, height;
{
 register struct BitMap *bm;

 if(depth > 8)
   return NULL;

 bm = (struct BitMap*)AllocMem(sizeof(struct BitMap), MEMF_CLEAR);
 if ( bm == NULL)
   return NULL;

 InitBitMap(bm, depth, width, height);

 /* takes care of freeing bitmap struct if it fails */
 if ( get_rasters(bm, width, height) == NULL)
   return NULL;

 return bm;
}   /*	end of getbitmap()  */



/* Ripoff notice : This code is pretty much straight out of the Transactor
 * volume 1, issue 3.  I modified it somewhat however.
 * It will nicely allocate all of the required bit plane pointers for your
 * specified bitmap structure.	Return NULL if something screws up.
 */
get_rasters(bm, width, height)
 register struct BitMap *bm;
 int width, height;
{
 register int i;
 register long size;

 size = bm->Rows * bm->BytesPerRow;

 for (i=0; i < bm->Depth; i++)
  {
   bm->Planes[i] = (PLANEPTR) AllocRaster( width, height);

   if (bm->Planes[i] == NULL)
    {
     MSG("No mem for BitMap data.  Exiting.\n");
     return free_bitmap(bm, width, height);
    }

   BltClear(bm->Planes[i], ((width/8) * height), 1L);
  }
 return 1;
}    /*  end of AllocRasters()  */


free_bitmap(bm, width, height)
 register struct BitMap *bm;
 int width, height;
{
 register int i;

 /* if a plane pointer is null, this for loop exits */
 for (i=0; bm->Planes[i] && i < bm->Depth; i++) {
       FreeRaster(bm->Planes[i], (LONG)width, (LONG)height);
 }

 FreeMem(bm, sizeof(struct BitMap));
 return NULL;
}   /*	end of FreeRasters()  */


killscreen(screen)
 register struct Screen *screen;
{
 register struct BitMap *bm = NULL;
 int width, height;

 /* just to make sure we aren't getting garbage */
 if(screen < 100)
   return;

 while(screen->FirstWindow != NULL)  /* still got windows on this screen */
   Delay(50L);    /* wait a while for the window to go away */


 if (screen->BitMap.Depth > 2) {
   bm = (struct BitMap *)screen->ExtData;
   width = screen->Width; height = screen->Height;
  }

 CloseScreen(screen);    /* do this first. */

 if(bm != NULL)
   free_bitmap(bm, width, height);
}


