/*                                                               -*- C -*-
 *  RASTPORT.C
 *
 *  (c)Copyright 1991 by Tobias Ferber,  All Rights Reserved
 */

/* $VER: $Id: rastport.c,v 1.1 1995/06/21 22:18:28 tf Exp $ */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/rastport.h>
#include <graphics/gfx.h>
#include <stdlib.h>

#include "rastport.h"

/* Prototypes */

extern void *AllocMem(ULONG, ULONG);
extern void FreeMem(void *,ULONG);

extern void InitBitMap( struct BitMap *, BYTE, UWORD, UWORD );
extern PLANEPTR AllocRaster(ULONG,ULONG);
extern void FreeRaster( PLANEPTR, USHORT, USHORT);
extern void InitRastPort(struct RastPort *rp);
extern void SetRast( struct RastPort *, UBYTE );

/**/

typedef struct rpnode {
  struct rpnode *succ, *pred;
  struct RastPort *rp;
  int width, height, depth; 
} rpnode_t;

static rpnode_t *rplist= (rpnode_t *)0;


/* remember bitmap dimensions for given rastport */
static int rp_set(struct RastPort *rp, int width, int height, int depth)
{
  int err= 0;

  if(rp)
  {
    rpnode_t *this= (rpnode_t *)malloc( sizeof(rpnode_t) );

    if(this)
    {
      this->pred= (rpnode_t *)0;

      if( (this->succ= rplist) )
        rplist->pred= this;

      rplist= this;

      this->rp     = rp;
      this->width  = width;
      this->height = height;
      this->depth  = depth;
    }
    else err= 2;
  }
  else err= 1;

  return err;
}


/* recall and then forget bitmap dimensions for given rastport */
static int rp_get(struct RastPort *rp, int *width, int *height, int *depth)
{
  int err= 0;

  if(rp)
  {
    rpnode_t *this;

    for(this= rplist; this; this= this->succ)
      if( (long)this->rp == (long)rp )
        break;

    if(this)
    {
      if(width)  *width  = this->width;
      if(height) *height = this->height;
      if(depth)  *depth  = this->depth;

      if(this->pred)
        this->pred->succ= this->succ;

      else
        rplist= this->succ;

      if(this->succ)
        this->succ->pred= this->pred;

      free(this);
    }
    else err= 1; /* rp not in list */
  }
  else err= 2; /* no rp */

  return err;
}


/****** rastport/rp_dispose **************************************************
*
*   NAME
*       rp_dispose -- Free a RastPort allocated via rp_new()
*
*   SYNOPSIS
*       nil= rp_dispose(rp);
*
*       struct RastPort *rp_dispose(struct RastPort *);
*
*   FUNCTION
*       This function returns all memory allocated for the given RastPort,
*       the attached rp->BitMap and all bitplanes to the system free pool.
*
*   INPUTS
*       rp            - A RastPort allocated vi rp_new()
*
*   RESULT
*       nil           - if rp has been allocated via rp_new() then
*                       (struct RastPort *)NULL will be returned,
*                       rp (unchanged), otherwise.
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*       rp_new()
*
******************************************************************************
*
*
*/

struct RastPort *rp_dispose(struct RastPort *rp)
{
  int width, height, depth;

  if( rp_get(rp, &width, &height, &depth) == 0 )
  {
    struct BitMap *bm= rp->BitMap;

    if(bm)
    {
      int p;

      for(p=0; p<depth; p++)
      {
        if(bm->Planes[p])
          FreeRaster(bm->Planes[p],width,height);
      }
      FreeMem( (void *)bm, sizeof(struct BitMap) );
    }
    FreeMem( (void *)rp, sizeof(struct RastPort) );
    rp= (struct RastPort *)0;
  }

  return rp;
}


/****** rastport/rp_new ******************************************************
*
*   NAME
*       rp_new -- Allocate a RastPort including a BitMap and Bitplanes
*
*   SYNOPSIS
*       rp= rp_new(width, height, depth);
*
*       struct RastPort *rp_new(int, int, int);
*
*   FUNCTION
*       This function allocates a new RastPort and attaches a new BitMap to
*       it with initialized, empty bitplanes.
*
*   INPUTS
*       width         -
*       height        -
*       depth         -
*
*   RESULT
*       rp            - A new RastPort
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*       rp_dispose()
*
******************************************************************************
*
*
*/

struct RastPort *rp_new(int width, int height, int depth)
{
  struct RastPort *rp= (struct RastPort *)0;

  if( (width > 0) && (height > 0) && (depth > 0) )
  {
    rp= (struct RastPort *)AllocMem( sizeof(struct RastPort), MEMF_PUBLIC|MEMF_CLEAR );

    if(rp)
    {
      struct BitMap *bm= (struct BitMap *)AllocMem( sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR );

      if(bm)
      {
        int p;

        InitBitMap(bm, depth, width, height);

        for(p=0; p<depth; p++)
        {
          PLANEPTR ptr= (PLANEPTR)AllocRaster(width,height);

          if(ptr)
            bm->Planes[p]= ptr;

          else
            break;
        }

        if(p == depth)
        {
          InitRastPort(rp);
          rp->BitMap= bm;
          SetRast(rp, 0L);

          rp_set(rp, width,height,depth);
        }

        else /* AllocRaster() failed for plane `p' */
        {
          for(--p; p>=0; p--)
          {
            if(bm->Planes[p])
              FreeRaster(bm->Planes[p],width,height);
          }
          FreeMem( (void *)bm, sizeof(struct BitMap) );
          bm= (struct BitMap *)0;
        }
      }
      else /* !bm */
      {
        FreeMem( (void *)rp, sizeof(struct RastPort) );
        rp= (struct RastPort *)0;
      }
    }
    else /* !rp */
      ;
  }

  return rp;
}
