P********************************
*                              *
*            SWISH             *
*                              *
* A striking example of kinetic*
* art.  Uses the hires routines*
* in HIRES.O.                  *
*------------------------------*
*    Glen E. Bredon 10/28/85   *
*------------------------------*
*     Merlin 128 assembler     *
********************************
*
* Example Merlin source file.
*
* RUN this via the BASIC program "SWISH".
*
* The program operates by keeping a table of the
* coordinates of the endpoints of a moving line
* segment.  The oldest line is erased before the
* new one is plotted.  The coordinates for the
* new line are contained from the last one by
* adding small increments (VEPS1 etc.).  When
* they are about to go out of bounds, the
* increments are updated by selecting random
* amounts of the opposite sign.

          EXP OFF
          TR

* Hires jump vectors (from HIRES.O file):

EXIT      = $1303         ;Reset text mode & mem status
GR        = $1306         ;Init hires screen & intface
TEXT      = $130C         ;Set text mode
HPLOT     = $130F         ;Plot pnt at XY,A
XPLOT     = $1312         ;Xplot pnt at YX,A
HLINE     = $1315         ;Line from last pnt to XA,Y
HCOLOR    = $1318         ;Set all colors using A,X,Y
HMASK     = $131B         ;Set dot color X=%00-%11

PL        = $FB           ;Pointer for printing title
FAC       = $61           ;Floating point acc & rnd seed
SEED      = $121B         ; used by included rnd # genr
FACSGN    = $66           ;Sign of fp #
EXTRA     = $70           ;Extra precision fp byte
SIGNIF    = $88B6         ;Fp normalization routine

CLRCHN    = $FFCC
GETIN     = $FFE4
CHROUT    = $FFD2

* Data:

MAXLEN    = 10*8

          AST 50

STADR     MAC
          LDA #]1
          STA ]2
          LDA #>]1
          STA ]2+1
          <<<

ADD       MAC             ;Used in RND routine
          LDA FAC+]1
          ADC SEED+]1
          STA FAC+]1
          <<<

ROT       MAC             ;Used in RND routine
          LDA SEED+]1
          ROL
          STA FAC+]1
          <<<

          ORG $5000

          JMP START       ;So we can call it easily

COLORS    DFB 6,7,2       ;Screen colors
MAX       DFB MAXLEN-1    ;# lines before erase
MASK      DFB 3           ;Max coor displacement
MINEPS    DFB 1           ;Min coor displacement
FIRSTH1   DFB 10          ;Initial coors
FIRSTV1   DFB 5           ; "
FIRSTH2   DFB 50          ; "
FIRSTV2   DFB 80          ; "
HSYM      DFB $80         ;Horiz sym flag (yes)
VSYM      DFB 0           ;Vert sym flag (no)

VTEMP     DFB 0           ;Scratch
INDEX     DFB 0           ;Pointer to this line
LASTINDX  DFB 1           ;Always = INDEX+1 mod MAX
HEPS1     DFB 0           ;Horiz epsilon: end 1
VEPS1     DFB 0           ;Vert  "
HEPS2     DFB 0           ;Horiz epsilon: end 2
VEPS2     DFB 0           ;Vert  "
HOR1      DFB 0           ;Scratch locations
VER1      DFB 0
HOR2      DFB 0
VER2      DFB 0
COLOR     DFB %11         ;Current color mask
XFLAG     DFB 0           ;Plot or Xplot flag

START     LDA #%00000010  ;Set ROM above $8000
          STA $FF00       ; RAM below
          JSR TEXT
          JSR CLRCHN
          LDA #$93        ;Clear screen
          JSR CHROUT
          STADR TITLE     ;PL
          LDY #0
]LOOP     LDA (PL),Y      ;Print instruction page
          BEQ :SENT
          JSR CHROUT
          INC PL
          BNE ]LOOP
          INC PL+1
          BNE ]LOOP
:SENT     CLI             ;Just in case
:WAIT     JSR GETIN       ;Wait for space bar
          CMP #' '
          BNE :WAIT
          JSR CLEAR       ;Set indices and clear screen
          JSR SETCOLOR    ;Set screen colors
          LDX #MAXLEN
          LDA #0          ;Clear coor of all lines
]LOOP     STA H1,X
          STA V1,X
          STA H2,X
          STA V2,X
          DEX
          BNE ]LOOP

          LDA FIRSTV1     ;Init coor of 1st line
          STA V1
          LDA FIRSTH1
          STA H1
          LDA FIRSTV2
          STA V2
          LDA FIRSTH2
          STA H2

* Set up epsilons:

          JSR RANDOMP
          STA HEPS1
          JSR RANDOMP
          STA VEPS1
          JSR RANDOMM
          STA HEPS2
          JSR RANDOMM
          STA VEPS2

*-------------------------------------
* Main program loop:
*
* First check for keypress.
*-------------------------------------

MAINLOOP  JSR GETIN       ;Key pressed?
          TAY
          BEQ :NOKEY      ;Skip if not
          AND #$7F
          CMP #$60
          BLT :OV
          AND #%01011111
:OV       CMP #'d'        ;A, B, or C ?
          BGE :ISE
          CMP #'a'
          BLT :ISE
          SBC #'a'        ;Convert to #0,1,2
          TAX
          DEC COLORS,X
          BNE :SC
          LDA #15         ;Skip color 0
          STA COLORS,X
:SC       JSR SETCOLOR    ;Call color set routine
          JMP :NOKEY
:ISE      CMP #'e'
          BNE :ISI
          LDA MINEPS
          EOR #3          ;Toggle min eps 1<->2
          STA MINEPS
          BNE :NOKEY      ;Always taken
:ISI      CMP #'i'
          BNE :ISH
          LDA MASK
          LSR             ;Halve mask (tail length)
:SM       STA MASK
          CMP #3          ;<3?
          LDA #%11111     ;Back to 31 if so
          BLT :SM
          BGE :NOKEY
:ISH      CMP #'h'
          BNE :ISV
          ROR
          EOR HSYM        ;Toggle high bit
          STA HSYM
          JMP :CL
:ISV      CMP #'v'
          BNE :CC
          ROR
          EOR VSYM        ;Toggle high bit
          STA VSYM
          JMP :CL
:CC       CMP #'C'&$1F    ;STOP key?
          BNE :ISNUM
          JMP EXIT
:ISNUM    EOR #'0'
          CMP #10         ;A digit?
          BGE :NOKEY      ;Skip if not
          ASL             ;x 8
          ASL
          ASL
          ADC #7          ;+ 7
          STA MAX
:CL       JSR CLEAR

* Last routine must be changed if MAXLEN
* changed and v.v.  Reminder of this:

          ERR 10*8-MAXLEN

:NOKEY    LDX #0
          STX XFLAG       ;Signal plot
          JSR HMASK       ;Set color black
          JSR LINE        ; & use to erase line
          LDA #$80        ;Signal xplot
          STA XFLAG

* Add or subtract epsilons to end coor of last
* line and use for the next line (at INDEX):

VADJ1     LDX LASTINDX    ;Vert adjust end 1
          LDA V1,X
          CLC
          ADC VEPS1       ;Add current epsilon
          BIT VEPS1       ;Epsilon + or - ?
          BMI :NEG        ;Branch if -
          CMP #200        ;Off bottom?
          BLT :OK
          BGE :JR         ;New epsilon if so
:NEG      BCS :OK         ;Branch if not off top
:JR       JSR RANDOM      ;Get new epsilon
          STA VEPS1
          JSR GETCOLOR    ;Change color mask
          LDX LASTINDX
          LDA V1,X        ;Use old coor if dir change
:OK       LDX INDEX
          STA V1,X        ;Save coor of next line

VADJ2     LDX LASTINDX    ;Vert adjust end 2
          LDA V2,X
          CLC
          ADC VEPS2
          BIT VEPS2
          BMI :NEG
          CMP #200
          BLT :OK
          BGE :JR
:NEG      BCS :OK
:JR       JSR RANDOM
          STA VEPS2
          JSR GETCOLOR
          LDX LASTINDX
          LDA V2,X
:OK       LDX INDEX
          STA V2,X

HADJ1     LDX LASTINDX    ;Horiz adjust end 1
          LDA H1,X
          CLC
          ADC HEPS1       ;Add horiz epsilon
          BIT HEPS1       ;Going right or left?
          BMI :NEG        ;Branch if left
          CMP #160
          BCC :OK         ;Branch if still on screen
          BCS :JR         ;Off screen, new epsilon
:NEG      BCS :OK         ;Branch if on screen
:JR       JSR RANDOM      ;Get new epsilon
          STA HEPS1
          JSR GETCOLOR
          LDX LASTINDX
          LDA H1,X
:OK       LDX INDEX
          STA H1,X

HADJ2     LDX LASTINDX    ;Horiz adjust end 2
          LDA H2,X
          CLC
          ADC HEPS2
          BIT HEPS2
          BMI :NEG
          CMP #160
          BCC :OK
          BCS :JR
:NEG      BCS :OK
:JR       JSR RANDOM
          STA HEPS2
          JSR GETCOLOR
          LDX LASTINDX
          LDA H2,X
:OK       LDX INDEX
          STA H2,X
          STX LASTINDX    ;Last index = index
          LDX COLOR
          JSR HMASK       ;Set dot mask for this line
          JSR LINE        ;Xplot line
          DEC INDEX       ;Bump index
          BPL :JM
          LDA MAX         ; mod max+1
          STA INDEX
:JM       JMP MAINLOOP    ;Loop forever

          AST 50
*
* Routine to draw/undraw line pointed to by INDEX:

LINE      LDX INDEX
          LDA H1,X        ;Get line coor
          BNE :SH1        ;Avoid 0 for true symmetry
          LDA #1
:SH1      STA HOR1        ;Save them so that X can
          LDA H2,X        ; be altered
          BNE :SH2
          LDA #1
:SH2      STA HOR2
          LDA V1,X
          STA VER1
          LDA V2,X
          STA VER2
          LDA VSYM        ;Get vert sym flag
          AND #$80        ;Strip low bits so ASL
          STA VTEMP       ; will clear carry 2nd time
RPT      
          LDY #0
          LDA HOR1        ;Double horiz coor (hires uses
          ASL             ; 0-319, this prog uses 0-159)
          BCC :XX1
          INY
:XX1      TAX
          LDA VER1
          JSR PLOT        ;Plot end point
          LDX #0
          LDA HOR2
          ASL
          BCC :XX2
          INX
:XX2      LDY VER2
          JSR HLINE       ;Draw/xdraw line
          BIT HSYM        ;Horiz sym wanted?
          BPL :NH         ;Branch if not
          LDA #160
          SEC
          SBC HOR1
          LDY #0
          ASL
          BCC :XX3
          INY
:XX3      TAX
          LDA VER1
          JSR PLOT
          LDA #160
          SEC
          SBC HOR2
          LDX #0
          ASL
          BCC :XX4
          INX
:XX4      LDY VER2
          JSR HLINE
:NH       ASL VTEMP       ;Vert sym wanted?
          BCC :RET        ;Branch if not or 2nd pass
          LDA #199
          SBC VER1
          STA VER1
          LDA #199
          SBC VER2
          STA VER2
          BCS RPT         ;Always taken
:RET      RTS

          AST 50
*
* Misc. subroutines:
*
* Routine to call color set hires routine
* from data in the 3 COLORS bytes:

SETCOLOR  LDA COLORS
          LUP 4
          ASL
          --^
          ORA COLORS+1
          TAX
          LDA COLORS+2
          LUP 4
          ASL
          --^
          ORA #3          ;Not needed
          LDY #0          ;= backgnd & border
          JMP HCOLOR

* Routine to get new color.  This is called
* when some endpoint reaches the edge:

GETCOLOR  JSR RND         ;Call random in hires
          LDA FAC+1
          AND #3          ;Isolate 2 bits
          BEQ GETCOLOR    ;Reject color 0
          STA COLOR
          RTS

RANDOM    BCS RANDOMM     ;Get neg random if CS
RANDOMP   JSR RND         ;Get random positive #
          LDA FAC+1       ; from 1 to MASK (approx)
          AND MASK        ;Mask < 4,8,16, or 32
          CLC
          ADC MINEPS      ;Make => 1 or 2
          RTS

RANDOMM   JSR RND         ;Get random negative #
          LDA FAC+1       ; from -MASK to -1 (approx)
          AND MASK
          SEC
          SBC MASK        ; <= 0
          SEC
          SBC MINEPS      ; <= -1 or -2
          RTS

          AST 50
*
* Superior random number generator.
* It is very fast (15 times faster than RND)
* and reasonably good (far better than RND).
*
* It uses the BASIC seed location so that it can
* be initialized by a BASIC RND command.

RND       LDA SEED+4
          ASL
          STA FAC+4
          ROT 3
          ROT 2
          ROT 1
          SEC
          ROL FAC+4
          ROL FAC+3
          ROL FAC+2
          ROL FAC+1
          CLC
          ADD 4
          TAX
          ADD 3
          TAY
          ADD 2
          ADD 1
          CLC
          LDA FAC+2
          ADC SEED+4
          STA SEED+2
          STA FAC+2
          LDA FAC+1
          ADC SEED+3
          STA SEED+1
          STA FAC+1
          STY SEED+3
          STX SEED+4
          LDA #$80
          STA FAC
          ASL
          STA EXTRA
          STA FACSGN
          JMP SIGNIF

CLEAR     LDX #0
          STX LASTINDX    ;Init INDEX & LASTINDX
          LDA MAX
          STA INDEX
          JMP GR          ;Do hires init

PLOT      BIT XFLAG
          BMI :DOX        ;Branch if xplot wanted
          JMP HPLOT       ;This used with black to erase
:DOX      JMP XPLOT       ;Mostly this is used

TITLE     HEX 0D0D0D
          ASC '                SWISH'0D0D
          ASC '           BY  GLEN BREDON'0D0D
          ASC 'HIT SPACE BAR TO START'0D0D
          ASC 'I   CHANGES MAX INCREMENT 32>16>8>4'0D
          ASC 'E   TOGGLES MIN INCREMENT 1<->2'0D
          ASC 'H   TOGGLES HORIZONTAL SYMMETRY'0D
          ASC 'V   TOGGLES VERTICAL SYMMETRY'0D
          ASC 'A   CHANGES COLOR #1'0D
          ASC 'B   CHANGES COLOR #2'0D
          ASC 'C   CHANGES COLOR #3'0D
          ASC '0-9 CHANGES LENGTH OF TAIL'0D
          ASC 'STOP TERMINATES PROGRAM'0D00

* Locations of line coor tables:

          ERR ^$6000      ;Make sure program doesn't
                          ; conflict with data area:

          DUMMY $6000

H1        DS MAXLEN
V1        DS MAXLEN
H2        DS MAXLEN
V2        DS MAXLEN

          ERR ^$8000      ;Must not be under ROM
          DEND
