/***************************************************************************
 *
 *                 MandelVroom Contour Editing Window
 *
 *                         Kevin L. Clague
 *
 *                        Copyright (C) 1987
 *
 **************************************************************************/

#include "mand.h"

extern struct Screen *screen;
extern struct RastPort *rp;
extern struct Window *MandWind;

extern SHORT MouseX,MouseY;

extern SHORT MaxCount;

extern struct Menu Menu[];

extern USHORT CmdMode;

extern SHORT Zoom;

USHORT CurContour;

struct Window *ContWind;

BYTE ContTitle[80];

struct NewWindow NewCont = {
   0,200-80,                 /* start position           */
   320,200,                  /* width, height            */
   (UBYTE) 0, (UBYTE) 1,     /* detail pen, block pen    */
                             /* IDCMP flags */
   MENUPICK | GADGETDOWN | GADGETUP | REQCLEAR | CLOSEWINDOW,
                             /* MandWind flags */
   WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH | NOCAREREFRESH,
   (struct Gadget *) NULL,   /* first gadget             */
   (struct Image *) NULL,    /* user checkmark           */
   (UBYTE *) NULL,           /* window title             */
   (struct Screen *) NULL,   /* pointer to screen        */
   (struct BitMap *) NULL,   /* pointer to superbitmap   */
   80,80,320,200,            /* sizing                   */
   CUSTOMSCREEN              /* type of screen           */
   };

SHORT Ceiling = 1023;

extern SHORT *CountBase;
extern SHORT CountX, CountY;

SHORT  Contours[NUMCONTS] = {
      1023,128,64, 32, 27, 26, 25, 24,
      23, 22, 21, 20, 19, 18, 17, 16,
      15, 14, 13, 12, 11, 10, 9,  8,
       7, 6,  5,  4,  3,  2,  1,  0
      };
SHORT *ContourBase = Contours;
SHORT  NumContours = NUMCONTS;

UBYTE  Colors[NUMCONTS] = {
      0,  1,  2,  3,  4,  5,  6,  7,
      8,  9,  10, 11, 12, 13, 14, 15,
      16, 17, 18, 19, 20, 21, 22, 23,
      24, 25, 26, 27, 28, 29, 30, 31
      };
UBYTE *ColorBase = Colors;

struct Gadget *ContGadget[NUMCONTS];
struct Gadget *SelGadget[NUMCONTS];


/*
 * Figure out what to do for this contour gadget
 */
DoContourDown(gadget)
  struct Gadget *gadget;
{
  USHORT  ContNum;
  USHORT  Type;

  extern LONG NavTop, NavBot, NavLeft, NavRight;

  ContNum = gadget->GadgetID & NUMMASK;

  switch (Type = gadget->GadgetID >> TYPEBITS & TYPEMASK) {
    case CONTCNTLS:
         switch (gadget->GadgetID) {
           case CONTRECOL:
                ReColor();
                DisplayBeep(screen);

                if (Zoom) {
                  DrawBox(NavLeft, NavTop, NavRight, NavBot );
                  DrawExtras(NavLeft, NavTop, NavRight, NavBot );
                }
                SetNormPointer();
                break;

           case CONTSMTH:
                SetToPointer();
                CmdMode = SMOOTH;
                break;
         }
         break;

    case CONTSELS:
         if (CmdMode == SMOOTH) {
           SetNormPointer();
           SmoothContours(CurContour, ContNum);

         } else {
           SetNormPointer();
           CmdMode = IMPLIEDSET;
         }
         break;

    case CONTDOWNS:
         if (*(ContourBase + ContNum) > 0) {
           *(ContourBase + ContNum) -= 1;
         }
         ReString(ContNum);
         SetNormPointer();
         break;

    case CONTUPS:
         if (*(ContourBase + ContNum) < MaxCount) {
           *(ContourBase + ContNum) += 1;
         }
         ReString(ContNum);
         SetNormPointer();
         break;
  }

  if ( Type != CONTCNTLS ) {
    DrawContBox(CurContour, 0);
    DrawContBox(ContNum, 1);

    CurContour = ContNum;
    SetContTitle(ContNum);
  }
}

/*
 * Figure out what to do for this contour gadget
 */
DoContourUp(gadget)
  struct Gadget *gadget;
{
  USHORT  ContNum;
  struct  PropInfo *PropInfo;
  ULONG   VertPot;
  char    msg[80];

  ContNum = gadget->GadgetID & NUMMASK;
  SetNormPointer();

  PropInfo = (struct PropInfo *) gadget->SpecialInfo;

  VertPot = PropInfo->VertPot + 1;

  switch (gadget->GadgetID >> TYPEBITS & TYPEMASK) {
    case CONTCNTLS:
         Ceiling = ((LONG) MaxCount - ( VertPot * MaxCount  >> 16));
         ModAll();
         break;

    case CONTPOTS:
         if (ContourBase[ContNum] < Ceiling) {
           ContourBase[ContNum] =
               ( (LONG) Ceiling ) - (VertPot * Ceiling >> 16);
         } else {
           PropInfo->VertPot = 0;
           RefreshGList(gadget,ContWind,NULL,1);
         }

         DrawContBox(CurContour, 0);
         DrawContBox(ContNum, 1);

         CurContour = ContNum;
         SetContTitle(ContNum);

         break;
  }
}

/*
 * Set the contour window's new title
 */
SetContTitle(ContNum)
  int ContNum;
{
  SHORT Low, High;

  char *fmt1 = "Contour: %d Alt: %d-%d Pen: %d";
  char *fmt2 = "Contour: %d Alt: %d Pen: %d";

  High = ContourBase[ContNum];

  if (ContNum != 0) {
    Low  = ContourBase[ContNum-1];

    if (Low == High || Low - High == 1) {
      sprintf(ContTitle, fmt2, ContNum, High, ColorBase[ContNum]);
    } else {
      sprintf(ContTitle, fmt1, ContNum, Low - 1, High, ColorBase[ContNum]);
    }
  } else {

    sprintf(ContTitle, fmt2, ContNum, MaxCount, High, ColorBase[ContNum]);
  }
  SetWindowTitles(ContWind, ContTitle, NULL);
}

/*
 * Set Potentiometer knob's pen
 */
DrawContBox(Contour, pen)
  ULONG Contour;
  int pen;
{
  LONG Left, Right, Top, Bottom;
  LONG Scaled4;
  struct RastPort *rp = ContWind->RPort;

  extern USHORT XScale, YScale;

  Scaled4 = 4 << XScale;

  Left = (6 << XScale) * Contour + Scaled4 - 1;
  Right = Left + Scaled4 + 1;

  Top = (12 << YScale) - 1;
  Bottom = Top + (4 << YScale) + 1;

  SetDrMd(rp, (LONG) JAM1);
  SetAPen(rp, (LONG) pen);
  /*
   * Draw the new box
   */
  Move(rp, Left,  Top   );
  Draw(rp, Right, Top   );
  Draw(rp, Right, Bottom);
  Draw(rp, Left,  Bottom);
  Draw(rp, Left,  Top+1 );

} /* DrawContBox */

/*
 *  There was a window pick. Do what we need to do to service it
 */
DoWindowPick(MouseX,MouseY)
  SHORT MouseX,MouseY;
{
  USHORT Height;

  if (MouseX >= LEFTMARG && MouseX <= MandWind->Width-RIGHTMARG &&
      MouseY >= TOPMARG  && MouseY <= MandWind->Height-BOTMARG) {

    if (CmdMode == IMPLIEDSET) {
      Height = *(CountBase + (MouseY-TOPMARG)*CountX + MouseX - LEFTMARG);
      *(ContourBase + CurContour) = Height;
      ReString(CurContour);
    }
  }
}

/*
 *  Smooth the heights over a subrange of contours
 */
SmoothContours(First,Second)
  USHORT First, Second;
{
  USHORT Temp;
  float Diff,Start;

  if (Second-First != 0) {

    if (Second < First) {
      Temp = First;
      First = Second;
      Second = Temp;
    }

    Start = (float) ContourBase[First];
    Diff = (((float) ContourBase[Second]) - Start)/((float)(Second-First));

    if (Diff > -1.0) {
      Diff = -1.0;
    }

    for ( ; First < Second && Start > 0; First++)
      ContourBase[First + 1] = (SHORT) (Start += Diff);

    if (Start == 0) {
      for ( ; First < NumContours; First++) {
        ContourBase[First] = 0;
      }
    }

    ModAll();
  }
} /* SmoothContours */

/*
 * ReColor the Mandelbrot image
 */
ReColor() {
  SHORT *CountPtr = CountBase;
  SHORT  Mask,Width;
  LONG   Mod,CMod;
  SHORT  LF,LP,RF,RP,D[6];
  SHORT  i,j,k,l, Depth;
  LONG   Sx,TL;
  SHORT *Planes[6];

  UBYTE *ColorPtr;
  UBYTE *ColorSave,t;
  UBYTE  T[1030];

  Depth = screen->BitMap.Depth;

  if (CountPtr == NULL) {
    DispErrMsg("No counts to recolor",0);
    return(0);
  }
  if (screen->Width < CountX+LEFTMARG+RIGHTMARG ||
      screen->Height < CountY+TOPMARG+BOTMARG) {
    DispErrMsg("Picture too big for screen.",0);
    return(0);
  }

  if (MandWind->Width  != CountX+LEFTMARG+RIGHTMARG ||
      MandWind->Height != CountY+TOPMARG+BOTMARG)
      SizeWindow(MandWind,CountX+LEFTMARG+RIGHTMARG-MandWind->Width,
                          CountY+TOPMARG+BOTMARG-MandWind->Height);

  WindowToFront(MandWind);

  SetAPen( rp, 0L );
  RectFill( rp, LEFTMARG, TOPMARG, LEFTMARG + CountX, TOPMARG + CountY );

  if ( Depth < 4 || Depth == 6) {
    ReColorSlow();
    return(0);
  }

  /* try to get enough memory to recolor the picture fast. */
  ColorPtr = ColorSave = (UBYTE *) AllocMem((LONG) CountX * CountY, 0L);
  if (ColorPtr == (UBYTE *) NULL) {
    ReColorSlow();
    return(0);
  }

  /* So recolor it now that you have the memory */
  for (i = 0,j = 1029; i < NUMCONTS; i++)
    for (; j >= ContourBase[i] && j; )
      T[j--] = ColorBase[i];
  while (j >= 0) T[j--] = 0;

  ;
#ifdef SLOW1
  for (Sx = CountX*CountY; Sx-- >= 0; )  *(ColorPtr++) = T[*(CountPtr++)];
#else
#asm
CountPtr  equ -4
ColorBase equ -82
T         equ -1117
   move.w   _CountX,d1
   muls.w   _CountY,d1
   sub.l    #1,d1
   move.l   CountPtr(a5),a0
   lea      T(a5),a1
   move.l   ColorBase(a5),a6
ColorLoop
   move.w   (a0)+,d0
   move.b   (a1,d0.w),(a6)+
   sub.l    #1,d1
   bge      ColorLoop
#endasm
#endif

  ClearMenuStrip(MandWind);

  if (Depth == 4) {
    ReColor4(ColorSave);
  } else
  if (Depth == 5) {
    ReColor5(ColorSave);
  }
  SetMenuStrip(MandWind, Menu);

  FreeMem(ColorSave,CountX*CountY);
} /* ReColor */

/*
 * Assembly code to recolor 4 bit planes
 */
ReColor4(ColorSave)
  UBYTE *ColorSave;
{
  SHORT  Mask,Width;
  LONG   Mod,CMod;
  SHORT  LF,LP,RF,RP;
  SHORT  i,j,k,l;
  LONG   Sx,TL;
  UBYTE  *ColorPtr;

  struct BitMap *BitMap = MandWind->RPort->BitMap;

#asm
SaveReg  reg a0-a6/d0-d7
Plane0   equ 8
Plane1   equ Plane0+4
Plane2   equ Plane0+8
Plane3   equ Plane0+12
Plane4   equ Plane0+16
Plane5   equ Plane0+20

BitMap    equ -44
ColorPtr  equ -40
TL        equ -36
Sx        equ -32
l         equ -28
k         equ -26
j         equ -24
i         equ -22
RP        equ -20
RF        equ -18
LP        equ -16
LF        equ -14
CMod      equ -12
Mod       equ -8
Width     equ -4
Mask      equ -2
ColorSave equ 8
#endasm

  ColorPtr = ColorSave;
  Sx = screen->Width >> 4;
  LF = MandWind->LeftEdge + 17 & 0xfff0;
  LP = MandWind->LeftEdge + LEFTMARG;
  CMod = CountX - (LF-LP);
  Mod = Sx - 1;
  TL = Sx * (MandWind->TopEdge + TOPMARG) + (LP >> 4);
  Width = LF-LP;
  Mask = 0xffff << Width;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                for (i = CountY; i; i--) {
Y0Loop4                            ; /* for each pixel in column */
  move.w  Width(a1),d7           ;  for (k = Width; k; k--) {
  eor.w   d2,d2                  ;  Clear all bits in the bit plane data regs.
  eor.w   d3,d3
  eor.w   d4,d4
  eor.w   d5,d5
B0Loop4
  move.b  (a0)+,d0               ;    d0 = *(ColorPtr++);
  asr.b   d1,d0                  ;    get low order bit from d0
  addx.w  d2,d2                  ;    put it in bit plane 0 data
  asr.b   d1,d0                  ;    same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                  ;    same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                  ;    same for bit plane 3
  addx.w  d5,d5
  sub.w   d1,d7                  ;    same for bit plane 5
  bgt     B0Loop4                ;  } /* did each bit in bit plane word */
  move.w  Mask(a1),d0            ;  Turn off all the new bits in planes
  and.w   d0,(a2)
  and.w   d0,(a3)
  and.w   d0,(a4)
  and.w   d0,(a5)
  or.w    d2,(a2)+               ;  Set the new bits in the bit planes
  or.w    d3,(a3)+
  or.w    d4,(a4)+
  or.w    d5,(a5)+
  move.l  Mod(a1),d0             ;  Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  adda.l  CMod(a1),a0            ;  Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     Y0Loop4
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm

  RP = LP + CountX & 0xfff0;
  RF = RP - 16;
  CMod = CountX - (RP-LF);
  Mod = Sx - ((RP-LF) >> 4);
  TL++;
  Width = (RP-LF) >> 4;
  ColorPtr = ColorSave + LF - LP;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)          ;i = CountY;
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                for (i = CountY; i; i--) {
YLoop4                            ; /* for each column */
  move.w  Width(a1),j(a1)        ;  for (j = Width; j; j--) {
XLoop4                               ; /* pack a word for each bit plane */
  move.w  #16,d7                 ;    for (k = 16; k; k--) {
BLoop4
  move.b  (a0)+,d0               ;      d0 = *(ColorPtr++);
  asr.b   d1,d0                  ;      get low order bit from d0
  addx.w  d2,d2                  ;      put it in bit plane 0 data
  asr.b   d1,d0                  ;      same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                  ;      same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                  ;      same for bit plane 3
  addx.w  d5,d5
  sub.w   d1,d7                  ;      same for bit plane 5
  bgt     BLoop4                 ;    } /* did each bit in bit plane word */
  move.w  d2,(a2)+               ;    Save the packed data in bit planes
  move.w  d3,(a3)+
  move.w  d4,(a4)+
  move.w  d5,(a5)+
  sub.w   d1,j(a1)               ;  } /* did each word in a row */
  tst.w   j(a1)
  bgt     XLoop4
  move.l  Mod(a1),d0             ;  Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  adda.l  CMod(a1),a0            ;  Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     YLoop4
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm

  TL += Width;
  Width = LP + CountX - RP;
  CMod = CountX - Width;
  Mod = Sx - 1;
  Mask = 0xffff >> Width;
  ColorPtr = ColorSave + RP - LP;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                ;for (i = CountY; i; i--) {
Y2Loop4                            ; /* for each pixel in column */
  move.w  Width(a1),d7           ;  for (k = Width; k; k--) {
  eor.w   d2,d2                  ;  Clear all bits in the bit plane data regs.
  eor.w   d3,d3
  eor.w   d4,d4
  eor.w   d5,d5
B2Loop4
  move.b  (a0)+,d0                ;   d0 = *(ColorPtr++);
  asr.b   d1,d0                   ;   get low order bit from d0
  addx.w  d2,d2                   ;   put it in bit plane 0 data
  asr.b   d1,d0                   ;   same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                   ;   same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                   ;   same for bit plane 3
  addx.w  d5,d5
  sub.w   d1,d7                   ;   same for bit plane 5
  bgt     B2Loop4                 ; } /* did each bit in bit plane word */
  move.w  Mask(a1),d0             ; Turn off all the new bits in planes
  and.w   d0,(a2)
  and.w   d0,(a3)
  and.w   d0,(a4)
  and.w   d0,(a5)
  move.w  #16,d0
  sub.w   Width(a1),d0
  asl.w   d0,d2
  asl.w   d0,d3
  asl.w   d0,d4
  asl.w   d0,d5
  or.w    d2,(a2)+                ; Set the new bits in the bit planes
  or.w    d3,(a3)+
  or.w    d4,(a4)+
  or.w    d5,(a5)+
  move.l  Mod(a1),d0              ; Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  adda.l  CMod(a1),a0             ; Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     Y2Loop4
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm
} /* ReColor 4 bit planes */


/*
 * Assembly code to recolor 5 bit planes
 */
ReColor5(ColorSave)
  UBYTE *ColorSave;
{
  SHORT  Mask,Width;
  LONG   Mod,CMod;
  SHORT  LF,LP,RF,RP;
  SHORT  i,j,k,l;
  LONG   Sx,TL;
  UBYTE  *ColorPtr;

  struct BitMap *BitMap = MandWind->RPort->BitMap;

  ColorPtr = ColorSave;
  Sx = screen->Width >> 4;
  LF = MandWind->LeftEdge + 17 & 0xfff0;
  LP = MandWind->LeftEdge + LEFTMARG;
  CMod = CountX - (LF-LP);
  Mod = Sx - 1;
  TL = Sx * (MandWind->TopEdge + TOPMARG) + (LP >> 4);
  Width = LF-LP;
  Mask = 0xffff << Width;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  Plane4(a0),a6          ;Same for fifth bit plane.
  adda.l  d0,a6
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                ;for (i = CountY; i; i--) {
Y0Loop5                            ; /* for each pixel in column */
  move.w  Width(a1),d7           ;  for (k = Width; k; k--) {
  eor.w   d2,d2                  ;  Clear all bits in the bit plane data regs.
  eor.w   d3,d3
  eor.w   d4,d4
  eor.w   d5,d5
  eor.w   d6,d6
B0Loop5
  move.b  (a0)+,d0               ;    d0 = *(ColorPtr++);
  asr.b   d1,d0                  ;    get low order bit from d0
  addx.w  d2,d2                  ;    put it in bit plane 0 data
  asr.b   d1,d0                  ;    same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                  ;    same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                  ;    same for bit plane 3
  addx.w  d5,d5
  asr.b   d1,d0                  ;    same for bit plane 4
  addx.w  d6,d6
  sub.w   d1,d7                  ;    same for bit plane 5
  bgt     B0Loop5                ;  } /* did each bit in bit plane word */
  move.w  Mask(a1),d0            ;  Turn off all the new bits in planes
  and.w   d0,(a2)
  and.w   d0,(a3)
  and.w   d0,(a4)
  and.w   d0,(a5)
  and.w   d0,(a6)
  or.w    d2,(a2)+               ;  Set the new bits in the bit planes
  or.w    d3,(a3)+
  or.w    d4,(a4)+
  or.w    d5,(a5)+
  or.w    d6,(a6)+
  move.l  Mod(a1),d0             ;  Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  add.l   d0,a6
  adda.l  CMod(a1),a0            ;  Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     Y0Loop5
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm

  RP = LP + CountX & 0xfff0;
  RF = RP - 16;
  CMod = CountX - (RP-LF);
  Mod = Sx - ((RP-LF) >> 4);
  TL++;
  Width = (RP-LF) >> 4;
  ColorPtr = ColorSave + LF - LP;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)          ;i = CountY;
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  Plane4(a0),a6          ;Same for fifth bit plane.
  adda.l  d0,a6
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                ;for (i = CountY; i; i--) {
YLoop5                            ; /* for each column */
  move.w  Width(a1),j(a1)        ;  for (j = Width; j; j--) {
XLoop5                               ; /* pack a word for each bit plane */
  move.w  #16,d7                 ;    for (k = 16; k; k--) {
BLoop5
  move.b  (a0)+,d0               ;      d0 = *(ColorPtr++);
  asr.b   d1,d0                  ;      get low order bit from d0
  addx.w  d2,d2                  ;      put it in bit plane 0 data
  asr.b   d1,d0                  ;      same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                  ;      same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                  ;      same for bit plane 3
  addx.w  d5,d5
  asr.b   d1,d0                  ;      same for bit plane 4
  addx.w  d6,d6
  sub.w   d1,d7                  ;      same for bit plane 5
  bgt     BLoop5                 ;    } /* did each bit in bit plane word */
  move.w  d2,(a2)+               ;    Save the packed data in bit planes
  move.w  d3,(a3)+
  move.w  d4,(a4)+
  move.w  d5,(a5)+
  move.w  d6,(a6)+
  sub.w   d1,j(a1)               ;  } /* did each word in a row */
  tst.w   j(a1)
  bgt     XLoop5
  move.l  Mod(a1),d0             ;  Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  add.l   d0,a6
  adda.l  CMod(a1),a0            ;  Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     YLoop5
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm

  TL += Width;
  Width = LP + CountX - RP;
  CMod = CountX - Width;
  Mod = Sx - 1;
  Mask = 0xffff >> Width;
  ColorPtr = ColorSave + RP - LP;

#asm
  movem.l SaveReg,-(sp)          ;Save all the gprs to the stack
  move.l  a5,a1                  ;We need a5, so put MANX stack in a1
  move.w  _CountY,i(a1)
  move.l  BitMap(a1),a0
  move.l  TL(a1),d0              ;Load Offset to Top,Left corner of screen
  asl.l   #1,d0                  ; and make it a 'word' offset
  move.l  Plane0(a0),a2          ;Get address of screens first bit plane
  adda.l  d0,a2                  ; add in window top-left offset.
  move.l  Plane1(a0),a3          ;Same for second bit plane.
  adda.l  d0,a3
  move.l  Plane2(a0),a4          ;Same for third bit plane.
  adda.l  d0,a4
  move.l  Plane3(a0),a5          ;Same for fourth bit plane.
  adda.l  d0,a5
  move.l  Plane4(a0),a6          ;Same for fifth bit plane.
  adda.l  d0,a6
  move.l  ColorPtr(a1),a0        ;Load up pointer to recolored data.
  move.l  #1,d1                  ;/* for each row */
;                                ;for (i = CountY; i; i--) {
Y2Loop5                          ;  ; /* for each pixel in column */
  move.w  Width(a1),d7           ;  for (k = Width; k; k--) {
  eor.w   d2,d2                  ;  Clear all bits in the bit plane data regs.
  eor.w   d3,d3
  eor.w   d4,d4
  eor.w   d5,d5
  eor.w   d6,d6
B2Loop5
  move.b  (a0)+,d0               ;    d0 = *(ColorPtr++);
  asr.b   d1,d0                  ;    get low order bit from d0
  addx.w  d2,d2                  ;    put it in bit plane 0 data
  asr.b   d1,d0                  ;    same for bit plane 1
  addx.w  d3,d3
  asr.b   d1,d0                  ;    same for bit plane 2
  addx.w  d4,d4
  asr.b   d1,d0                  ;    same for bit plane 3
  addx.w  d5,d5
  asr.b   d1,d0                  ;    same for bit plane 4
  addx.w  d6,d6
  sub.w   d1,d7                  ;    same for bit plane 5
  bgt     B2Loop5                ;  } /* did each bit in bit plane word */
  move.w  Mask(a1),d0            ;  Turn off all the new bits in planes
  and.w   d0,(a2)
  and.w   d0,(a3)
  and.w   d0,(a4)
  and.w   d0,(a5)
  and.w   d0,(a6)
  move.w  #16,d0
  sub.w   Width(a1),d0
  asl.w   d0,d2
  asl.w   d0,d3
  asl.w   d0,d4
  asl.w   d0,d5
  asl.w   d0,d6
  or.w    d2,(a2)+               ;  Set the new bits in the bit planes
  or.w    d3,(a3)+
  or.w    d4,(a4)+
  or.w    d5,(a5)+
  or.w    d6,(a6)+
  move.l  Mod(a1),d0             ;  Adjust plane pointers to start of next line
  add.l   d0,d0
  add.l   d0,a2
  add.l   d0,a3
  add.l   d0,a4
  add.l   d0,a5
  add.l   d0,a6
  adda.l  CMod(a1),a0            ;  Adjust color pointer to start of next line
  sub.w   d1,i(a1)               ;} /* did each row */
  tst.w   i(a1)
  bgt     Y2Loop5
  movem.l (sp)+,SaveReg          ;better restore the registers
#endasm
} /* ReColor 5 bit planes */

ReColorSlow() {
  LONG i, j, x, y, xl, yl;
  SHORT *CountPtr = CountBase;
  UBYTE  T[1030];
  UBYTE  OldColor;
  UBYTE  NewColor;

  j = MaxCount;

  for (i = 0; i < NUMCONTS && j >= 0; i++)
    for (; j >= ContourBase[i] && j >=0 ; )
      T[j--] = ColorBase[i];
  while (j >= 0) T[j--] = 0;

  OldColor = 0xff;
  xl = CountX + LEFTMARG;
  yl = CountY + TOPMARG;

  for (y = TOPMARG; y < yl; y++) {
    for (x = LEFTMARG; x < xl; x++) {

      NewColor = T[ *CountPtr++ ];

      if ( NewColor != OldColor) {

        SetAPen( rp, NewColor );
        OldColor = NewColor;
      }
      if (NewColor)
        WritePixel(rp, x, y);
    }
  }
} /* ReColorSlow */

/*
 * Allocate all the gadgets and things for the contour window
 */
struct Gadget *MakeContours()
{
  struct Gadget *FirstGadget, *NextGadget, *OldGadget;

  extern struct Gadget *MakeBool(), *MakePot();
  extern struct IntuiText *MakeIntui();

  USHORT i,x,y;
  UBYTE c = 0;

  struct PropInfo *PropInfo;

  FirstGadget = OldGadget = MakePot(228, 26, 4, 32, CONTCEIL, 0);

  if (OldGadget == (struct Gadget *) NULL)
    goto error;

  for (x = y = 0; x < 2; y += 10, x++) {

    NextGadget = MakeBool(234,y+14,6,6,1,CONTCNTL+x);

    if (NextGadget == (struct Gadget *) NULL)
      goto error;

    switch (x) {
      case 0:
        NextGadget->GadgetText = MakeIntui("ReColor",10,-1,3,3,JAM1);
        break;
      case 1:
        NextGadget->GadgetText = MakeIntui("Smooth",10,-1,3,3,JAM1);
        break;
    }
    OldGadget->NextGadget = NextGadget;
    OldGadget = NextGadget;
  }

  for (x = y = 0; y < NumContours; x += 6, y++) {

    NextGadget = MakeBool(4+x, 12,4,4,Colors[y],CONTSEL+y);

    if (NextGadget == (struct Gadget *) NULL)
      goto error;

    OldGadget->NextGadget = NextGadget;
    OldGadget = SelGadget[y] = NextGadget;
  }
  NextGadget->GadgetText = MakeIntui("Set",6,-2,3,3,JAM1);

  for (x = y = 0; y < NumContours; x += 6, y++) {

    NextGadget = MakeBool(4+x, 18, 4, 4, 3, CONTUP + y);

    if (NextGadget == (struct Gadget *) NULL)
      goto error;

    OldGadget->NextGadget = NextGadget;
    OldGadget = NextGadget;
  }
  NextGadget->GadgetText = MakeIntui("+",6,-2,3,3,JAM1);

  /*
   * Allocate the potentiometer gadgets for contour window
   */
  for (x = y = 0; y < NumContours; x += 6, y++) {

    NextGadget = MakePot(4+x, 24, 4, 32, CONTPOT+y, y);

    if (NextGadget == (struct Gadget *) NULL)
      goto error;

    PropInfo = (struct PropInfo *) NextGadget->SpecialInfo;

    if (ContourBase[y] < Ceiling) {

      PropInfo->VertPot =

      (USHORT) ((((Ceiling - (ContourBase[y] + 1))<<16)/(Ceiling)) & 0xffff);

    } else
      PropInfo->VertPot = 0;

    OldGadget->NextGadget = NextGadget;
    ContGadget[y] = NextGadget;
    OldGadget = NextGadget;
  }
  NextGadget->GadgetText = MakeIntui("Alt.",6,12,3,3,JAM1);

  /*
   * Allocate the push button gadgets for decrementing contours
   */
  for (x = y = 0; y < NumContours; x += 6, y++) {

    NextGadget = MakeBool(4+x, 58, 4, 4, 3, CONTDOWN + y);

    if (NextGadget == (struct Gadget *) NULL)
      goto error;

    if (y == NUMCONTS - 1) {
      NextGadget->GadgetText = MakeIntui("-",6,-2,3,3,JAM1);
    }
    OldGadget->NextGadget = NextGadget;
    OldGadget = NextGadget;
  }
  return( FirstGadget );

error:
  FreeGadgets(FirstGadget);
  return((struct Gadget *) NULL);

} /* MakeContours */

/*
 * Open the Contour window
 */
OpenContWind()
{
  struct Window *OpenMyWind();
  struct Gadget *gadgets;

  extern USHORT YScale;

  if (ContWind == (struct Window *) NULL) {

    gadgets = MakeContours();

    if (gadgets == (struct Gadget *) NULL) {
      DispErrMsg("Can't allocate contour gadget chain",0);
      return(0);
    }

    NewCont.TopEdge = 119 << YScale;

    ContWind = OpenMyWind(&NewCont, screen, gadgets, 320, 80, 320, 80);

    if (ContWind == (struct Window *) NULL) {
      DispErrMsg("Can't open Contour window",0);
      FreeGadgets(gadgets);
      return(0);
    }
    SetContTitle(0);
    DrawContBox(CurContour);
    ForceNormPointer();
  } else {
    WindowToFront( ContWind );
  }
  return(1);
} /* OpenContWind */

/*
 * Close the Mand window
 */
CloseContWind()
{
  if (ContWind != (struct Window *) NULL) {
    CloseMyWind(ContWind,NewCont.FirstGadget);
    ContWind = (struct Window *) NULL;
  }
} /* ClosePalWind */

/*
 * ReDisplay a given contour potentiometer gadget
 */
ReString(PotNum)
  SHORT PotNum;
{
  SHORT i;
  USHORT VertPot;

  if (ContourBase[PotNum] < Ceiling)
    VertPot = (USHORT) ((((Ceiling - (ContourBase[PotNum]+1))<<16)/(Ceiling)) & 0xffff);
  else
    VertPot = (USHORT) 0;
  NewModifyProp(ContGadget[PotNum], ContWind, NULL, FREEVERT | PROPBORDERLESS,
                0L, VertPot, 0L, 0L, 1L);
} /* ReString */

/*
 * ReDisplay all the contour potentiometer gadgets
 */
ModAll()
{
  SHORT i;
  USHORT VertPot;
  struct Gadget *PropGad = (struct Gadget *) ContGadget[0];

  for (i = 0; i < NUMCONTS; i++) {
    if (ContourBase[i] < Ceiling) {
      VertPot = (USHORT) ((((Ceiling - (ContourBase[i] + 1))<<16)/(Ceiling)) & 0xffff);
    } else
      VertPot = (USHORT) 0;
    NewModifyProp(PropGad,ContWind,NULL,FREEVERT|PROPBORDERLESS,0L,VertPot,0L,0L,1L);
    PropGad = PropGad->NextGadget;
  }
} /* ModAll */
