/*
 * MandelVroom 2.0
 *
 * (c) Copyright 1987,1989  Kevin L. Clague, San Jose, CA
 *
 * All rights reserved.
 *
 * Permission is hereby granted to distribute this program's source
 * executable, and documentation for non-comercial purposes, so long as the
 * copyright notices are not removed from the sources, executable or
 * documentation.  This program may not be distributed for a profit without
 * the express written consent of the author Kevin L. Clague.
 *
 * This program is not in the public domain.
 *
 * Fred Fish is expressly granted permission to distribute this program's
 * source and executable as part of the "Fred Fish freely redistributable
 * Amiga software library."
 *
 * Permission is expressly granted for this program and it's source to be
 * distributed as part of the Amicus Amiga software disks, and the
 * First Amiga User Group's Hot Mix disks.
 *
 * contents: this file contains functions to redraw (or repaint) Mandelbrot
 * and Julia projects.  There are special high-performance functions to
 * recolor 4 and 5 bit plane pictures (in assembly).  There is also a
 * function that can spawn off a child task to redraw the picture (for the
 * other number of bit planes 1,2,3 and 6)
 */

#include "mandp.h"

extern LONG pSigMask;

/*
 * ReColor a picture into a window
 */
ReColor( Pict )
  register struct Picture *Pict;
{
  /* This set of variables should not be rearranged or moved.
     There is Assembly language used in this routine, to increase
     performance.  The assembly code depends on these variables
     being located on Manx's stack.  Obviously it is not too portable
     or maintainable, but it is faster.
   */
  SHORT *CountPtr;
  UBYTE *ColorPtr;

  register LONG CountX, CountY;

  /* These variables are O.K. to rearrange and add to. */

  register struct Window  *Window;
  register LONG   dx,dy;

  LONG i, Depth;

  UBYTE *ColorSave;

  LONG   wx,wy,Sx;

  if ( Pict == NULL )
    return;

  KillReColor( Pict );
  FreeScrollTemp( Pict );
  PauseChild(Pict);

  Window = Pict->Window;
  CountPtr = Pict->Counts;
  CountX = Pict->CountX;
  CountY = Pict->CountY;

  Depth = screen->BitMap.Depth;

  if (CountPtr == NULL || Pict->Flags & NO_RAM_GENERATE ) {
    DispErrMsg("No counts to recolor",0);
    return;
  }

  wx = CountX + Pict->LeftMarg + Pict->RightMarg;
  wy = CountY + Pict->TopMarg  + Pict->BotMarg;

  dx = screen->Width  - wx;
  dy = screen->Height - wy;

  if ( dx < 0 || dy < 0 ) {
    DispErrMsg("Picture too big for screen.",0);
    return;
  }

  dx -= Window->LeftEdge;
  dy -= Window->TopEdge;

  if ( dx < 0 || dy < 0 ) {
    MoveWindow( Window, dx, dy );
  }

  dx = wx - Window->Width;
  dy = wy - Window->Height;

  if ( dx || dy ) {

    SizeWindow(Window, dx, dy );

    /* Spin till the window gets resized */
    /* Gross eh? */

    i = 0;

    while (i++ < 10000 && Window->Width != wx && Window->Height != wy);

    if (i == 10000) {
      DispErrMsg("can't resize the window");
      return;
    }

    BorderWindow(Window);
  }

  if (Pict->CurLine+Pict->TopMarg < Pict->Window->Height-Pict->BotMarg-1) {

    SetAPen(  Pict->Window->RPort, NORMALPEN );
    RectFill( Pict->Window->RPort, Pict->LeftMarg,
              Pict->CurLine        + Pict->TopMarg,
              Pict->Window->Width  - Pict->RightMarg - 1,
              Pict->Window->Height - Pict->BotMarg   - 1);
  }

  Pict->Flags &= ~LENS_DISPLAYED;

  MakeColorXlate( Pict );

  if ( Depth != 4 && Depth != 5) {
    ReColorSlow( Pict );
    return;
  }

  /* try to get enough memory to recolor the picture fast. */

  ColorPtr = ColorSave =
           (UBYTE *) safeAllocMem( CountX * CountY + 1, 0L);

  if (ColorPtr == (UBYTE *) NULL) {
    ReColorSlow( Pict );
    return;
  }

  WindowToFront(Window);
  ClearMenuStrip(Window);

  Delay(8);

  LockLayers( BackWind->WLayer->LayerInfo );

  /* We were able to allocate enough memory to translate the entire
     picture from heights to pens.  The array of pens is used to
     quickly recolor the screen using Recolor4 or Recolor5 */

  /* If you don't like the assembly, you can use this C instead */

#define SLOW1
#ifdef SLOW1
  for (Sx = CountX*CountY; Sx-- >= 0; )
    *(ColorPtr++) = *(Pict->ClrXlate + *(CountPtr++));

#else
#asm
CountPtr  equ -4                     ; these define where your variables
ColorBase equ -8                     ; are located on Manx's stack
   move.w   d4,d1                    ; this is ugly, but CountX is in d4
   muls.w   d5,d1                    ; and CountY is in d5
   sub.l    #1,d1
   move.l   CountPtr(a5),a0
   move.l   _ColorXlate,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

  if (Depth == 4) {
    ReColor4( ColorSave, Pict);
  } else
  if (Depth == 5) {
    ReColor5( ColorSave, Pict);
  }
  UnlockLayers( BackWind->WLayer->LayerInfo );
  AwakenChild(Pict);

  SetMenuStrip(Window, Menu);

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

MakeColorXlate( Pict )
  register struct Picture *Pict;
{
  register LONG i,j;

  /* So prepare the color translate table */
  for (i = 0,j = 1023; i < NumContours; i++)
    for (; j >= Pict->Heights[i] && j > 0; )
     *(Pict->ClrXlate + j--) = Pict->Pens[i];
  while (j >= 0) *(Pict->ClrXlate + j--) = 0;
}

/*
 * Assembly code to recolor 4 bit planes
 */
ReColor4(ColorSave, Pict)
  UBYTE *ColorSave;
  register struct Picture *Pict;
{
  /* This set of variables should not be rearranged or moved.
     There is Assembly language used in this routine, to increase
     performance.  The assembly code depends on these variables
     being located on Manx's stack.  Obviously it is not too portable
     or maintainable, but it is faster.
   */
  SHORT  Mask,Width;
  LONG   Mod,CMod;
  SHORT  LF,LP,RF,RP;
  SHORT  i,j,k,l;
  LONG   Sx,TL;
  UBYTE  *ColorPtr;

  struct BitMap *BitMap;

  /* This can be messed with */

  SHORT  CountX, CountY;

  register struct Window  *Window;

#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

CountX    equ -50
CountY    equ -48
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

  Window = Pict->Window;
  BitMap = Window->RPort->BitMap;
  CountX = Pict->CountX;
  CountY = Pict->CurLine;

  ColorPtr = ColorSave;
  Sx = (screen->Width + 15) >> 4;
  LP = Window->LeftEdge + Pict->LeftMarg;
  LF = (LP + 15) & 0xfff0;
  CMod = Pict->CountX - (LF-LP);
  Mod = Sx - 1;
  TL = Sx *  (Window->TopEdge + Pict->TopMarg) + (LP-1 >> 4);
  Width = LF-LP;
  Mask = 0xffff << Width;

  if ( Width > 0 ) {

#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(a5),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 + Pict->CountX & 0xfff0;
  RF = RP - 16;
  CMod = Pict->CountX - (RP-LF);
  Mod = Sx - ((RP-LF) >> 4);
  TL++;
  Width = (RP-LF) >> 4;
  ColorPtr = ColorSave + LF - LP;

  if (Width > 0 ) {

#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(a5),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 + Pict->CountX - RP;
  CMod = Pict->CountX - Width;
  Mod = Sx - 1;
  Mask = 0xffff >> Width;
  ColorPtr = ColorSave + RP - LP;

  if ( Width > 0 ) {

#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(a5),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, Pict)
  UBYTE *ColorSave;
  register struct Picture *Pict;
{
  /* This set of variables should not be rearranged or moved.
     There is Assembly language used in this routine, to increase
     performance.  The assembly code depends on these variables
     being located on Manx's stack.  Obviously it is not too portable
     or maintainable, but it is faster.
   */
  SHORT  Mask,Width;
  LONG   Mod,CMod;
  SHORT  LF,LP,RF,RP;
  SHORT  i,j,k,l;
  LONG   Sx,TL;
  UBYTE  *ColorPtr;

  struct BitMap *BitMap;

  /* These can be messed with */

  SHORT  CountX, CountY;

  register struct Window  *Window;

  Window = Pict->Window;
  BitMap = Window->RPort->BitMap;

  CountX = Pict->CountX;
  CountY = Pict->CurLine;

  ColorPtr = ColorSave;
  Sx = (screen->Width + 15) >> 4;
  LP = Window->LeftEdge + Pict->LeftMarg;
  LF = (LP + 15) & 0xfff0;
  CMod = CountX - (LF-LP);
  Mod = Sx - 1;
  TL = Sx *  (Window->TopEdge + Pict->TopMarg) + (LP-1 >> 4);
  Width = LF-LP;
  Mask = 0xffff << Width;

  if ( Width > 0 ) {

#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(a5),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;

  if ( Width > 0 ) {

#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(a5),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;

  if ( Width > 0 ) {
#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(a5),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 */

static struct Picture *ReColorPict;

ReColorSlow( Pict )
  register struct Picture *Pict;
{
  int ReColorTask();

  WindowToFront(Pict->Window);

  Pict->ColorState = GENERATESTATE;

  ReColorPict = Pict;

  Pict->cTask = CreateTask( "ReColor", 0, ReColorTask, 1024);

  if ( Pict->cTask == NULL ) {
    DispErrMsg("Could not create recolor task",0);
  }

  /* Do this so we are sure child is done with ReColorPict */

  Wait( pSigMask );
}

ReColorTask( )
{
  register struct Picture  *Pict;
  register struct RastPort *Rp;
  register UBYTE  OldColor, NewColor;

  register LONG   x, y;
           LONG   xl, yl;

  SHORT *CountPtr;

  struct Window *Window;

  geta4();

  Pict = ReColorPict;

  /* Signal Parent that we have accessed ReColorPict */

  Signal( mTask, pSigMask );

  Window = Pict->Window;
  Pict->ColorChildState = RECOLORINCOMPLETE;

  Rp = Window->RPort;
  CountPtr = Pict->Counts;

  OldColor = 0xff;

  xl = Pict->CountX  + Pict->LeftMarg;
  yl = Pict->CurLine + Pict->TopMarg;

  for (y = Pict->TopMarg; y < yl; y++) {

    ObtainSemaphore( &Pict->WindowSemi );

    OldColor = *(Pict->ClrXlate + *CountPtr);
    Move( Rp, Pict->LeftMarg, y);

    for (x = Pict->LeftMarg; x < xl; x++) {

      NewColor = *(Pict->ClrXlate + *CountPtr++);

      if ( NewColor != OldColor) {

        SetAPen( Rp, OldColor );

        if ( x < Window->Width - Window->BorderRight) {
          Draw( Rp, x, y);
        }

        OldColor = NewColor;
      }
    }
    SetAPen( Rp, NewColor );
    Draw( Rp, x-1, y);

    ReleaseSemaphore( &Pict->WindowSemi );

    ReColorPause( Pict );
  }
  Pict->ColorChildState = RECOLORCOMPLETE;

  /* Indicate that generation has finished for this task */

  Signal( mTask, mSigMask );               /* signal parent as to change */

  while (Pict->ColorState != PAUSESTATE) ;

  ReColorPause(Pict);  /* signal back so parent doesn't hang */
} /* ReColorTask */

KillReColor( Pict )
  register struct Picture *Pict;
{
  register struct Task *cTask;

  if ( cTask = Pict->cTask ) {

    PauseReColor( Pict );
    DeleteTask( cTask );
    Pict->cTask = NULL;
  }
}

