/*
 * AMIGA.C: This is the Graphics Window interface to MetaFont for online
 * displays on the Commodore Amiga.  This file was written by Edmund Mergl
 * for his Amiga port of TeX 3.1 and MetaFont 2.7 from the original Unix
 * sources (see Fish Disks 611-616).
 *
 * Some modifications and improvements were made by Andreas and
 * Stefan Scherer, Abt-Wolf-Strasse 17, 96215 Lichtenfels, Germany:
 *
 *	- We use the `memory hack', so the values for `screenwidth'
 *	  and `screendepth' are to be found in `mfmemory.config'.  The
 *	  display height should be set to an InterLace value, this will
 *	  be dealt with by `lacefactor' (see below).
 *
 *	- The display window is no longer resizeable, because no
 *	  `screenupdate' is called and the picture is destroyed.
 *
 *	- Based upon an idea by Stefan Becker used in his famous MetaFont
 *	  port to the Amiga from 1991 (see Fish Disk 486) there is a variable
 *	  `scalefactor', which can be set to a (small) positiv integer in
 *	  `mfmemory.config'.  This results in a reduced size of the displayed
 *	  characters, so that large font pictures can be drawn on small-sized
 *	  screens (although some distortions will occur for `SF > 1').
 *
 *	- By replacing `Move' and `Draw' with `WritePixelLine' and friends
 *	  the speed of the display was heavily increased.
 *
 *	- The display screen is totally controlled by `screenwidth' and
 *	  `screendepth' from `mfmemory.config', when you set `screen_rows'
 *	  and `screen_cols' both to the maximum value `4095' in your local
 *	  device modes file.  MetaFont takes the smaller of these pairs.
 *
 *	- `blankrectangle' *always* set the complete display window to the
 *	  background color, not only the area specified by `left', `right',
 *	  `top', and `bottom'.  These MetaFont coordinates are now obeyed.
 *
 *	August 12, 1993.
 *
 *	- The changes for `Computers and Typesetting -- Volume A-E' provided
 *	  by Addison-Wesley Publishing Company resulted in MetaFont 2.71.
 *	  This caused a change in the window title.
 *
 *	September 11, 1993.
 *
 *      - The official version 2.71 has the same window title.
 *
 *      October 22, 1993.
 *
 *      - Although SAS/C has an AutoOpen feature for Amiga libraries,
 *        it is better to define the library bases explicitly.
 *
 *      January 28, 1994.
 *
 *      - Here's my new address:
 *        Andreas Scherer, Roland-Strasse 16, 52070 Aachen, Germany.
 *        <scherer@genesis.informatik.rwth-aachen.de> (Internet).
 *      - Make `amiga.c' compliant with the syntax of the other modules
 *        in the Web2C 6.1 distribution.
 *
 *      February 15, 1995.
 *
 *      - `close_all()' must not have arguments, because we want to
 *        link it into the `atexit()' function list.
 *      - To distinguish this version from the old distribution, the
 *        window title is modified.
 *
 *      February 19, 1995.
 *
 *      - MetaFont has the new version number 2.718.
 *
 *      March 23, 1995.
 *
 *      - rename `screenheight' to `screendepth' for consistency.
 *
 *      April 9, 1995.
 */

#define	EXTERN	extern
#include "../mfd.h"

#ifdef AMIWIN		/* Whole file */

#include <stdarg.h>

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

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

struct Screen *Scr;
struct Window *Win;

struct BitMap tempbm;
struct RastPort temprp;

UBYTE *linearray;

int scaledwidth  = 0;
int scaledheight = 0;

#ifndef scalefactor
#define scalefactor 1
#endif

/*
 * The configuration `mfmemory.config' holds values for `screenwidth' and
 * `screendepth' that always refer to an InterLace screen.  In case you
 * open the display on a non-InterLace screen, only half the lines are
 * shown to you.  This is automatically done by reading the screen
 * information and setting `lacefactor'.
 */
int lacefactor;

#define BACKGROUNDCOLOR	0
#define PENCOLOR	1

#define PUBSCREEN	0

/*
 * Allocating memory for the array used in `WritePixelLine' needs
 * WORD-aligned arguments.
 */
#define ALIGN_SIXTEEN_BIT(A) ((((A)+15)/16)*16)
#define min(a,b) ((a)<(b)?(a):(b))

/*
 * CLOSE_ALL: Clean up on MetaFont termination.  This routine has to
 * be called just before leaving the program, which is done automatically
 * when it gets entered into the `atexit' function list.
 */
void close_all(void)
{

  if (linearray)        free(linearray);
  if (tempbm.Planes[0]) FreeRaster(tempbm.Planes[0], scaledwidth, 1);
  if (Win)              CloseWindow(Win);
  if (GfxBase)          CloseLibrary((struct Library *)GfxBase);
  if (IntuitionBase)    CloseLibrary((struct Library *)IntuitionBase);

} /* close_all() */

/*
 * INITSCREEN: Initialize the physical display window on the WorkBench
 * screen of the Commodore Amiga.  Open the necessary libraries and open
 * the window according to `screenwidth' and `screendepth' as given in
 * the configuration file `mfmemory.config'.  For this purpose, the
 * `OpenWindowTagList' routine was replaced with `OpenWindowTags'.
 * The `WFLG_SIZEGADGET' window flag has been removed; resizing the
 * window kills the picture and never triggered an `updatescreen'.
 */
boolean mf_ami_initscreen(void)
{
#ifdef DEBUG
  printf("\ninitscreen()\n");
#endif

  if (!(IntuitionBase = (struct IntuitionBase *)
    OpenLibrary((unsigned char *)"intuition.library",(unsigned long)37L)))
  {
    fprintf(stderr,"\nCan't open intuition library. V37 required.\n");
    close_all();
    return(FALSE);
  }

  if (!(GfxBase = (struct GfxBase *)
    OpenLibrary((unsigned char *)"graphics.library",(unsigned long )37L)))
  {
    fprintf(stderr,"\nCan't open intuition library. V37 required.\n");
    close_all();
    return(FALSE);
  }

  if (!(Scr = LockPubScreen(PUBSCREEN)))
  {
    fprintf(stderr,"\nCan't get lock on public screen (0).\n");
    close_all();
    return(FALSE);
  }

  scaledwidth  = screenwidth/scalefactor;
  scaledheight = screendepth/scalefactor;
  lacefactor  = ((Scr->ViewPort.Modes & LACE) ? 1 : 2);

  if (!(Win = (struct Window *)OpenWindowTags( NULL,
	WA_InnerWidth,  scaledwidth,
	WA_InnerHeight, scaledheight/lacefactor,
	WA_Flags,       WFLG_DRAGBAR|WFLG_DEPTHGADGET,
	WA_AutoAdjust,  FALSE,
	WA_Title,       (ULONG)" MetaFont V2.718 Online Display",
	WA_PubScreen,   (ULONG)Scr,
	TAG_DONE)))
  {

#ifdef VARMEM
    fprintf(stderr,
       "\nCan't open online display window at size %d times %d.\n"
       "Change your configuration file.\n",screenwidth,screendepth);
    close_all();
#else
    fprintf(stderr,
       "\nCan't open online display window at size %d times %d.\n"
       "If you really absolutely need more capacity,\n"
       "you can ask a wizard to enlarge me.\n",screenwidth,screendepth);
    close_all();
#endif /* VARMEM */

    return(FALSE);
  }

  InitBitMap(&tempbm, 1, scaledwidth, 1);

  tempbm.Planes[0] = NULL;

  if(!(tempbm.Planes[0] = (PLANEPTR)AllocRaster(scaledwidth, 1)))
     return(FALSE);

  InitRastPort(&temprp);

  temprp.BitMap = &tempbm;

  if(!(linearray = (UBYTE *)
     calloc(ALIGN_SIXTEEN_BIT(scaledwidth),sizeof(UBYTE))))
     return(FALSE);

  UnlockPubScreen(NULL, Scr);

#ifdef DEBUG
   printf("initscreen() ok\n");
#endif

   return(TRUE);

} /* mf_ami_initscreen() */

/*
 * UPDATESCREEN: I really don't know what this function is supposed
 * to do, but its return type was declared and should be a numeric value.
 */
boolean mf_ami_updatescreen(void)
{
#ifdef DEBUG
  printf("updatescreen()\n");
#endif

  return(TRUE);

} /* mf_ami_update_screen() */

/*
 * BLANKRECTANGLE: Reset the drawing rectangle bounded by
 * ([left,right],[top,bottom]) to the background color.
 * This routine also now return `TRUE' after processing.
 */
boolean mf_ami_blankrectangle(screencol left,
                              screencol right,
                              screenrow top,
                              screenrow bottom)
{
#ifdef DEBUG
  printf("blankrectangle() - left: %d right: %d top: %d bottom: %d\n",
    left, right, top, bottom);
#endif

  SetAPen (Win->RPort, BACKGROUNDCOLOR);
  RectFill(Win->RPort,
    (SHORT)(Win->BorderLeft + left/scalefactor),
    (SHORT)(Win->BorderTop + top/(scalefactor*lacefactor)),
    (SHORT)(Win->BorderLeft + right/scalefactor - 1),
    (SHORT)(Win->BorderTop + bottom/(scalefactor*lacefactor) - 1));

  return(TRUE);

} /* mf_ami_blankrectangle() */

/*
 * PAINTROW: Paint a `row' starting with color `init_color', up to the
 * next transition specified by `transition_vector', switch colors, and
 * continue for `vector_size' transitions.  This function never returned
 * anything, so `TRUE' seems to be a good value.  Also, it now only
 * draws into the display window when a new raster line will be affected.
 * A lot of pre-drawing and inter-drawing calculations and conditionals
 * are evaluated to prepare a fast and clean drawing under the most
 * circumstances to be expected on the Amiga.  InterLace/Lace is taken
 * care of and the sizes are set appropriately not to clobber der borders.
 * (Don't ask me why this works; at least on my machine with my config.)
 */
boolean mf_ami_paintrow(screenrow row,
                        pixelcolor init_color, 
                        transspec transition_vector,
                        screencol vector_size)
{
  int start, scaledstart, scaledrow, scaledlaced;
  register int i=0, j=0, col, color;

#ifdef DEBUG
    printf("paintrow() - vector size: %d\n", vector_size);
#endif

  color       = ((0 == init_color) ? BACKGROUNDCOLOR : PENCOLOR);
  scaledlaced = scalefactor * lacefactor;
  start       = *transition_vector++;
  scaledstart = start / scalefactor;
  scaledrow   = row / scaledlaced;

  ReadPixelLine8(Win->RPort, Win->BorderLeft + scaledstart,
    Win->BorderTop + scaledrow, scaledwidth - scaledstart,
    linearray, &temprp);

  if(scalefactor>1) {

    do {
      for(col = *transition_vector++; i<col-start; i++) {
        linearray[j] |= color;
        if((i%scalefactor)==0) j++;
      }

      color = PENCOLOR - color;

#ifdef DEBUG
      printf("move col: %d row: %d ", col, row);
      printf("draw col: %d row: %d\n", (*transition_vector)-1, row);
#endif

    } while (--vector_size);

    if(i >= col-start) linearray[++j] |= color;

  } else {

    do {
      for(col = *transition_vector++; j<col-start; j++) {
         linearray[j] |= color;
         }

      color = PENCOLOR - color;

#ifdef DEBUG
      printf("move col: %d row: %d ", col, row);
      printf("draw col: %d row: %d\n", (*transition_vector)-1, row);
#endif

    } while (--vector_size);
  }

  if( (  Win->BorderTop + scaledrow ) <
      (  Win->Height - Win->BorderBottom ) )
    WritePixelLine8(Win->RPort, Win->BorderLeft + scaledstart,
      Win->BorderTop + scaledrow,
      min(Win->Width - Win->BorderLeft - Win->BorderRight - scaledstart,j),
      linearray, &temprp);

  return(TRUE);

} /* mf_ami_paintrow() */

#else
int ami_dummy;
#endif /* AMIWIN */
