;****************************************************************************
;
; GoLDSub - Routinen für 'Game of Life - Duo'
;
;****************************************************************************
;
; void SetCell(bmap,x,y,col)
;
;   Sets the cell at coordinates (x,y) to the color 'col'.
;     Here x and y are not pixel-coordinates but 'cell-coordinates', i.e.
;   the position of the cell is at window position (4x,3y).
;     The BitMap is assumed to have 2 Planes and there is no check for
;   legal coordinate values.
;
;****************************************************************************
;
; void ScanAgar(Agar,AuxAgar,CellTrans,xsize,ysize,cs)
;
;   From 'Agar' the new types of the cells which change in the current
;   cycle are computed and stored in 'AuxAgar'.
;     'Agar' and 'AuxAgar' are character arrays of 'xsize' columns and
;   'ysize' lines. 'CellTrans' is an array with 'cs' columns and as many
;   lines as there are different types of cells. 'CellTrans[i][j]' contains
;   the type of the cell into which a cell of type i has to be changed when
;   the sum of the eight neighbouring cells yields j.
;
;****************************************************************************
;
; void ChangeAgar(bm,Agar,AuxAgar,xsize,ysize,xoffset,yoffset)
;
;   The new types of the cells which change in the current cycle are read
;   from 'AuxAgar' and used to update 'Agar' and the display.
;     (xoffset,yoffset) are the cell-coordinates of the upper left corner
;   of the output area in the BitMat 'bm'.
;
;****************************************************************************
;
; void DisplayAgar(bm,Agar,xsize,ysize,xoffset,yoffset)
;
;   The 'Agar' of size 'xsize' x 'ysize' is displayed in the BitMap 'bm' at
;   cell-coordinates (xoffset,yoffset).
;
;****************************************************************************
;
; void CountCells(Agar,BluSum,RedSum,Len)
;
;   The number of blue and red cells in 'Agar' (which is interpreted as a
;   character string of length 'Len + 1') is returned in '*BluSum' and
;   '*RedSum', resp.
;
;****************************************************************************
;
; Created by
;              Andreas Neubacher
;
;              Hausleitnerweg 26
;              4020 Linz
;              Austria
;
;              E-mail: aneubach@risc.uni-linz.ac.at (Internet)
;                       k318577@alijku11            (Bitnet)
;
;****************************************************************************
;
;  Copyright notice:
;  I don't claim any copyright and put this code into the public domain.
;
;****************************************************************************
;
; 92-01-19  AN : Finished release version
;
;****************************************************************************


 section GoLDSub,code

;****************************************************************************

 xdef _SetCell  ;         C entry : void SetCell(bmap, x, y, col);
                ;                     struct BitMap *bmap;
                ;                             short x,y,col;
 xdef SetCell   ; Assembler entry :               A0   D0 D0 D1
                ;                                      hi lo
_SetCell
  movea.l   4(SP),A0
  move.l    8(SP),D0
  swap      D0
  move.w    14(SP),D0
  move.l    16(SP),D1

; Register usage
;
; D0 ... x/y (hi-/lo-word), mask for nibble set/clear
; D1 ... col; offset for the byte, which contains the second line of the cell
; D2 ... offset for the byte, which contains the first line of the cell
; A0 ... pointer to the BitMap
; A1 ... pointer to the Bitplane

SetCell
  move.l    D2,-(SP)
  swap      D1
  move.w    (A0),D1                 ; D1 := bmap->BytesPerRow
  move.w    D1,D2
  add.w     D2,D2
  add.w     D1,D2                   ; D2 := 3 * bmap->BytesPerRow
  mulu.w    D0,D2                   ;                             * y

  swap      D0
  lsr.w     #1,D0
  bcs       ELSE1                   ; IF x even THEN
    add.w     D0,D2                 ;   D2 := D2 + x/2
    move.l    #$008F0070,D0         ;   D0 := maske for high nibble
    bra       ENDIF1
ELSE1                               ; ELSE
    add.w     D0,D2                 ;   D2 := D2 + x/2
    move.l    #$00F80007,D0         ;   D0 := maske for low nibble
ENDIF1                              ; ENDIF
  add.w     D2,D1                   ; D1 := D2 + bmap->BytesPerRow

  movea.l   8(A0),A1                ; A1 points to first Bitplane
  btst      #16,D1
  beq       ELSE2                   ; IF col odd THEN
    or.b      D0,(A1,D2.w)          ;   set cell
    or.b      D0,(A1,D1.w)          ;   set cell
    bra       ENDIF2
ELSE2                               ; ELSE
    swap      D0
    and.b     D0,(A1,D2.w)          ;   clear cell
    and.b     D0,(A1,D1.w)          ;   clear cell
    swap      D0
ENDIF2                              ; ENDIF

  movea.l   12(A0),A1               ; A1 points to second Bitplane
  btst      #17,D1
  beq       ELSE3                   ; IF col > 1 THEN
    or.b      D0,(A1,D2.w)          ;   set cell
    or.b      D0,(A1,D1.w)          ;   set cell
    bra       ENDIF3
ELSE3                               ; ELSE
    swap      D0
    and.b     D0,(A1,D2.w)          ;   clear cell
    and.b     D0,(A1,D1.w)          ;   clear cell
ENDIF3                              ; ENDIF

  move.l    (SP)+,D2
  rts


;****************************************************************************


 xdef _ScanAgar ;         C entry : void ScanAgar(a, aa, ct, xs, ys, cs);
                ;                      char *a,*aa,*ct;
                ;                     short xs,ys,cs;
 xdef ScanAgar  ; Assembler entry :               A0 A1  A2  D0  D1  D2

_ScanAgar
  movea.l   4(SP),A0
  movea.l   8(SP),A1
  movea.l   12(SP),A2
  move.l    16(SP),D0
  move.l    20(SP),D1
  move.l    24(SP),D2

; Register usage
;
; D0 ... 'xs'
; D1 ... 'ys', row counter
; D2 ... 'cs', sum of cell values
; D3 ... column counter
; A0 ... 'a'
; A1 ... 'aa'
; A2 ... 'ct'
; A3/A4 ... auxiliary pointers into 'a'
; A5/A6 ... pointers to second/third line of matrix 'ct'

ScanAgar
  movem.l   D3/A3-A6,-(SP)

  movea.l   A0,A3
  adda.w    D0,A3
  movea.l   A3,A4
  adda.w    D0,A4
  adda.w    D0,A1
  addq.l    #1,A1

  movea.l   A2,A5
  adda.w    D2,A5
  movea.l   A5,A6
  adda.w    D2,A6

  moveq     #0,D2
  subq.w    #3,D0                       ; xs := xs - 3
  subq.w    #3,D1                       ; ys := ys - 3
REPEAT1                                 ; REPEAT
  move.w    D0,D3                       ;   D3 := xs
REPEAT2                                 ;   REPEAT
      move.b    (A0)+,D2                ;     D2 := sum over
      add.b     (A0),D2                 ;           the eight
      add.b     1(A0),D2                ;           neighbours
      add.b     (A3)+,D2                ;           of the
      add.b     1(A3),D2                ;           current
      add.b     (A4)+,D2                ;           cell
      add.b     (A4),D2                 ;
      add.b     1(A4),D2                ;
      btst      #0,(A3)
      beq       ELSE4                   ;     IF current cell = 1 THEN
        move.b    (A5,D2.w),(A1)+       ;       curr. aux. cell := ct[1][D2]
        bra       ENDIF4
ELSE4 btst      #1,(A3)
      bne       ELSE5                   ;     ELSE IF current cell = 0 THEN
        move.b    (A2,D2.w),(A1)+       ;       curr. aux. cell := ct[0][D2]
        bra       ENDIF4
ELSE5                                   ;     ELSE
        move.b    (A6,D2.w),(A1)+       ;       curr. aux. cell := ct[2][D2]
ENDIF4                                  ;     ENDIF
    dbf       D3,REPEAT2                ;   UNTIL row finished
    addq.l    #2,A0
    addq.l    #2,A1                     ;   next
    addq.l    #2,A3                     ;   row
    addq.l    #2,A4
  dbf       D1,REPEAT1                  ; UNTIL all rows finished

  movem.l   (SP)+,D3/A3-A6
  rts


;****************************************************************************


 xdef _ChangeAgar ;         C entry : void ChangeAgar(bm, a, aa, xs, ys, xo, yo);
                  ;                     struct BitMap *bm;
                  ;                              char *a,*aa;
                  ;                             short xs,ys,xo,yo;
 xdef ChangeAgar  ; Assembler entry :                 A0  A1 A2  D0  D1  D2  D2
                  ;                                                      hi  lo
_ChangeAgar
  movea.l   4(SP),A0
  movea.l   8(SP),A1
  movea.l   12(SP),A2
  move.l    16(SP),D0
  move.l    20(SP),D1
  move.l    24(SP),D2
  swap      D2
  move.w    30(SP),D2

; Register usage
;
; D0 ... x/y (hi-/lo-word)
; D1 ... value of current cell; color
; D2 ... x-offset
; D3 ... column counter
; D4 ... row counter
; D5 ... 'xs'
; D6 ... y-offset
; A0 ... 'bm'
; A2 ... pointer to current cell in 'aa'
; A3 ... pointer to current cell in 'a'

ChangeAgar
  movem.l   D2-D6/A3,-(SP)

  movea.l   A1,A3
  add.w     D0,A2
  addq.l    #1,A2
  add.w     D0,A3
  addq.l    #1,A3
  subq.w    #3,D0
  subq.w    #3,D1
  move.w    D1,D4
  move.w    D2,D6
  add.w     D1,D6
  swap      D2
  add.w     D0,D2
  move.w    D0,D5

REPEAT3                                 ; REPEAT
    move.w    D5,D3
REPEAT4                                 ;   REPEAT
      move.b    (A2),D1                 ;     D1 := current cell in 'aa'
      bne       ELSE6                   ;     IF D1 = 0 THEN
        move.b    D1,(A3)               ;       current cell in 'a' := D1
        moveq     #2,D1                 ;       color := 2
        bra       ENDIF7                ;       GOTO ENDIF7
ELSE6 cmp.b     #2,D1
      bgt       ENDIF6                  ;     ELSE IF D1 < 3 THEN
        beq       ELSE7                 ;       IF D1 = 1 THEN
          move.b    D1,(A3)             ;         current cell in 'a' := D1
          moveq     #0,D1               ;         color := 0
        bra       ENDIF7                ;       ELSE
ELSE7     move.b    D1,(A3)             ;         current cell in 'a' := D1
          moveq     #1,D1               ;         color := 1
ENDIF7                                  ;       ENDIF
        move.w      D2,D0
        sub.w       D3,D0
        swap        D0
        move.w      D6,D0
        sub.w       D4,D0
        jsr         SetCell             ;       SetCell(bm,D2-D3,D6-D4,color)
ENDIF6                                  ;     ENDIF
      addq.l      #1,A2                 ;     next
      addq.l      #1,A3                 ;     cell
    dbf         D3,REPEAT4              ;   UNTIL row finished
    addq.l      #2,A2                   ;   next
    addq.l      #2,A3                   ;   row
  dbf         D4,REPEAT3                ; UNTIL all rows finished

  movem.l   (SP)+,D2-D6/A3
  rts


;****************************************************************************


 xdef _DisplayAgar  ;         C entry : void DisplayAgar(bm, a, xs, ys, xo, yo);
                    ;                     struct BitMap *bm;
                    ;                              char *a;
                    ;                             short xs,ys,xo,yo;
 xdef DisplayAgar   ; Assembler entry :                  A0  A2 D0  D1  D2  D2
                    ;                                                   hi lo
_DisplayAgar
  movea.l   4(SP),A0
  movea.l   8(SP),A2
  move.l    12(SP),D0
  move.l    16(SP),D1
  move.l    20(SP),D2
  swap      D2
  move.w    26(SP),D2

; Register usage
;
; D0 ... x/y (hi-/lo-word)
; D1 ... value of current cell; color
; D2 ... x-offset
; D3 ... y-offset
; D4 ... 'xs'
; D5 ... column counter
; D6 ... line counter
; A0 ... 'bm'
; A2 ... pointer to current cell in 'a'

DisplayAgar
  movem.l   D3-D6,-(SP)

  add.w     D0,A2
  addq.l    #1,A2
  subq.w    #3,D0
  subq.w    #3,D1
  move.w    D1,D3
  add.w     D2,D3
  move.w    D1,D6
  swap      D2
  add.w     D0,D2
  move.w    D0,D4

REPEAT5                                 ; REPEAT
    move.w    D4,D5
REPEAT6                                 ;   REPEAT
      move.b    (A2)+,D1                ;     D1 := current cell in 'a'
      bne       ELSE8                   ;     IF D1 = 0 THEN
        moveq     #2,D1                 ;       color := 2
        bra       ENDIF8                ;
ELSE8 btst      #0,D1
      beq       ELSE9                   ;     ELSE IF D1 = 1 THEN
        moveq     #0,D1                 ;       color := 0
        bra       ENDIF8                ;     ELSE
ELSE9   moveq     #1,D1                 ;       color := 1
ENDIF8                                  ;     ENDIF
      move.w      D2,D0
      sub.w       D5,D0
      swap        D0
      move.w      D3,D0
      sub.w       D6,D0
      jsr         SetCell               ;     SetCell(bm,D2-D5,D3-D6,color)
    dbf         D5,REPEAT6              ;   UNTIL row finished
    addq.l      #2,A2                   ;   next row
  dbf         D6,REPEAT5                ; UNTIL all rows finished

  movem.l   (SP)+,D3-D6
  rts


;****************************************************************************


 xdef _CountCells ;         C entry : void CountCells(a, bluc, redc, len);
                  ;                              char *a;
                  ;                             short *redc,*bluc;
                  ;                     unsigned short len;
 xdef CountCells  ; Assembler entry :                 A0 A1    A2    D0

_CountCells
  movea.l   4(SP),A0
  movea.l   8(SP),A1
  movea.l   12(SP),A2
  move.l    16(SP),D0

; Register usage
;
; D0 ... cell counter
; D1 ... counter for blue cells
; D2 ... counter for red cells
; D3 ... current cell
; A0 ... pointer to current cell
; A1 ... 'bluc'
; A2 ... 'redc'

CountCells
  movem.l   D2/D3,-(SP)

  moveq.l   #0,D1
  move.l    D1,D2
REPEAT7                                 ; REPEAT
    move.b    (A0)+,D3                  ;   get current cell
    bne       ELSE10                    ;   IF cell = 0 THEN
      addq.w    #1,D1                   ;     blue cell
      bra       ENDIF10
ELSE10
    btst      #0,D3
    bne       ENDIF10                   ;   ELSE IF cell = 2 THEN
      addq.w    #1,D2                   ;     red cell
ENDIF10                                 ;   ENDIF
  dbf       D0,REPEAT7                  ; UNTIL all cells finished

  move.w    D1,(A1)
  move.w    D2,(A2)

  movem.l   (SP)+,D2/D3
  rts

 END

