home *** CD-ROM | disk | FTP | other *** search
- ; THE ULTIMATE SCREEN SAVER
- ; by Richard Leinecker
- ; Copyright 1989 by ST-LOG
-
- Kbdvbase = $22
- Supexec = $26
- Ptermres = $31
-
- GEMDOS = 1
- XBIOS = 14
-
-
- **********************************************************************
- *************************** start of program *************************
- **********************************************************************
-
- .text
-
- start:
- movea.l a7,a5 ; copy a7 for base page calc
- movea.l #ustk,a7 ; init adr for local stack
-
- move.l #setup,-(sp) ; put address of set up routine on stack
- move.w #Supexec,-(sp) ; SUPER mode command
- trap #XBIOS ; execute setup routine in SUPERVISOR mode
- addq.l #6,sp ; restore the stack pointer
-
-
- **********************************************************************
- * Insert keyboard patch *
- **********************************************************************
-
- move.w #Kbdvbase,-(sp) ; XBIOS to get vectors
- trap #XBIOS ; do the trap
- addq.l #2,sp ; clean up stack
- add.l #32,d0 ; +32 to get the keyboard vector address
- movea.l d0,a0 ; put it in a0
- move.l (a0),keyvector ; move the vector to keyvector
-
- movea.l #insert,a0 ; address of the jmp in the patch
- adda.l #2,a0 ; adjust it
- move.l keyvector,(a0) ; now put the keyboard vector in place
-
- movea.l d0,a0 ; get address of patch
- move.l #trapper,(a0) ; install it
-
- move.l #newmem,d0 ; new screen memory into d0
- andi.l #$fffffe00,d0 ; assure 512 byte boundary
- addi.l #512,d0
- move.l d0,newscreen ; put this value in newscreen
-
- **********************************************************************
- * calculate amount of memory to keep, then terminate! *
- **********************************************************************
-
- movea.l 4(a5),a5 ; basepage address
- move.l $c(a5),d0 ; length of text segment
- add.l $14(a5),d0 ; length of data segment
- add.l $1c(a5),d0 ; length of bss segment
- add.l #$100,d0 ; allow for basepage
-
- clr.w -(sp) ; specify exit code
- move.l d0,-(sp) ; length of block to keep
- move.w #Ptermres,-(sp) ; Terminate and stay resident
- trap #GEMDOS ; This doesn't return!
-
- **********************************************************************
- * Install the vertical blank interrupt *
- **********************************************************************
-
- setup:
- move.w #0,d1 ; set the counter to zero
- movea.l #$456,a0 ; load a0 with address of the pointer to the vector table
- movea.l (a0),a1 ; load a1 with the address of the vector table
-
- move.w #0,d0 ; zero the color
- move.w d0,vbiflag ; set the flag to 0
-
- movea.l #$454,a2 ; nvbls
- move.w (a2),d3 ; get the number of vector slots
-
- adda.l #4,a1
- check:
- move.l (a1),d2 ; put the vector address in d2
- cmpi.l #0,d2 ; see if it is a null
- beq install ; if it is null then go to the install phase
- addq.w #1,d1 ; add one to the counter
- cmp.w d3,d1 ; see if all 8 slots have been checked
- beq skip ; skip it if there are no slots left
- adda.l #4,a1 ; increment a1 to the next vector slot
- bra check ; go back and check the next vector slot
-
- install:
- move.l #vbi,(a1) ; install the vbi address in the vacant slot
- rts ; then leave
-
- skip:
- rts ; leave
-
-
- **********************************************************************
- * Here is the interrupt code *
- **********************************************************************
-
- vbi:
- move.w vbiflag,d0 ; see if the fireworks are going off
- cmpi.w #1,d0 ; 1 means yes
- bne continue ; if not, keep counting
-
- ; firework 1
-
- movea.l #fw1,a0 ; copy firework data to the
- movea.l #fcolor,a1 ; work area - first assign the
- jsr assign ; pointers then jsr 'assign'
- jsr realvbi ; do the actual firework stuff
- movea.l #fw1,a1 ; copy the work area back to
- movea.l #fcolor,a0 ; the firework data
- jsr assign
-
- ; firework 2
-
- movea.l #fw2,a0 ; copy firework data to the
- movea.l #fcolor,a1 ; work area - first assign the
- jsr assign ; pointers then jsr 'assign'
- jsr realvbi ; do the actual firework stuff
- movea.l #fw2,a1 ; copy the work area back to
- movea.l #fcolor,a0 ; the firework data
- jsr assign
-
- ; firework 3
-
- movea.l #fw3,a0 ; copy firework data to the
- movea.l #fcolor,a1 ; work area - first assign the
- jsr assign ; pointers then jsr 'assign'
- jsr realvbi ; do the actual firework stuff
- movea.l #fw3,a1 ; copy the work area back to
- movea.l #fcolor,a0 ; the firework data
- jsr assign
-
- ; firework 4
-
- movea.l #fw4,a0 ; copy firework data to the
- movea.l #fcolor,a1 ; work area - first assign the
- jsr assign ; pointers then jsr 'assign'
- jsr realvbi ; do the actual firework stuff
- movea.l #fw4,a1 ; copy the work area back to
- movea.l #fcolor,a0 ; the firework data
- jsr assign
-
- rts ; leave, all 4 fireworks done
-
- realvbi:
- move.w fnum,d0 ; see if there are fireworks going off
- cmpi.w #0,d0 ; are there any?
- bne makefw ; If so, go there
-
- move.w fcolor,d0 ; load the color
- move.w ty,d1 ; load the y coordinate
- move.w tx,d2 ; load the x coordinate
- jsr pixel ; XOR the old pixel
-
- move.w ty,d1 ; load the y coordinate
- move.w tx,d2 ; load the x coordinate
- subq.w #1,d1 ; decrement by delta y
- move.w trajectory,d4 ; load the trajectory number
- cmpi.w #0,d4 ; is it zero?
- bne notleft
- addq.w #1,d2 ; is it one?
- bra notside
-
- notleft:
- cmpi.w #3,d4
- bne notside
- subq.w #1,d2
-
- notside:
- move.w d2,tx ; save tx
- move.w d1,ty ; save ty
-
- cmp.w fheight,d1 ; compare with the intended height
- bgt makepixel ; if not there, just make a pixel
-
- move.w #0,numcount ; zero the explosion counter
- move.w #1,fnum ; set fnum to the small pattern
- move.w #0,fwvblanks ; zero the counter
- jsr drawfw ; jump and XOR the fw explosion
- rts ; leave
-
- makefw:
- move.w fwvblanks,d0 ; load the counter
- addq.w #1,d0 ; increment it
- cmpi.w #4,d0 ; see if a delay has passed
- beq delaygone ; go on if so
- move.w d0,fwvblanks ; store the value
- rts ; leave
-
- delaygone:
- move.w #0,fwvblanks ; zero the counter
- jsr drawfw ; jump and XOR the fw explosion
- move.w fnum,d0 ; load from fnum
- addq.w #1,d0 ; increment the counter
- move.w d0,fnum ; store it
- cmpi.w #9,d0 ; have there been seven patterns
- beq is_nine ; go on if not
- jsr drawfw ; jump and XOR the fw explosion
- rts ; leave
-
- is_nine:
- move.w numcount,d0 ; load numcount
- addq.w #1,d0 ; increment counter
- move.w d0,numcount ; store it
- move.w numexplode,d1 ; load explosion number
- cmp.w d0,d1 ; compare them
- beq is_done ; firework explosions finished!
-
- move.w #1,fnum ; reset fnum to 1
-
- movea.l #$4bc,a0 ; pointer to system clock
-
- move.w (a0),d0 ; get the value
- move.w colormask,d1
- and.w d1,d0 ; mask to use maximum colors only
- cmpi.w #0,d0
- bne nzero1
- ori.w #1,d0 ; insure plane one
- nzero1:
- move.w d0,fcolor ; store in fcolor
-
- move.w (a0),d0 ; get a number
- andi.w #15,d0 ; and it to assure value in range
- move.w (a0),d3 ; get another number
- andi.w #7,d3 ; and it to assure value in range
- move.w tx,d1 ; load x coordinate
- move.w ty,d2 ; load y coordinate
- subi.w #7,d1 ; subtract 4
- subi.w #4,d2 ; subtract 4
- add.w d0,d1 ; add the random value
- add.w d3,d2 ; add the other random value
- move.w d1,tx ; store it
- move.w d2,ty ; store it
-
- jsr drawfw ; make the pattern
- rts ; leave
-
- is_done:
- move.w #0,fnum ; zero fnum
-
- movea.l #$4bc,a0 ; pointer to system clock
-
- move.w (a0),d0 ; get the value
- move.w colormask,d1
- and.w d1,d0 ; mask to use maximum colors only
- cmpi.w #0,d0
- bne nzero2
- ori.w #1,d0 ; insure plane one
- nzero2:
- move.w d0,fcolor ; store in fcolor
-
- move.w (a0),d4 ; now get another value
- andi.w #31,d4 ; and it to insure value is in range
- addi.w #40,d4 ; add 31
- move.w d4,fheight ; store in fheight
-
- move.w (a0),d4 ; get another random number
- andi.w #3,d4 ; and it to assure value is in range
- addq.w #1,d4 ; add one
- move.w d4,numexplode ; store the value
-
- move.w (a0),d4 ; get yet another value
- andi.w #3,d4 ; and it to assure value is in range
- move.w d4,trajectory ; store in trajectory
- mulu onethird,d4 ; adjust the starting point
- add.w fromleft,d4 ; according to resolution
-
- move.w #199,ty ; store the y coordinate starting point
- move.w #199,d1 ; put 199 in d1
- move.w d4,tx ; store the x coordinate starting point
- move.w d4,d2 ; store x value
-
- makepixel:
- move.w fcolor,d0 ; move the color into d0
- jsr pixel ; goto the pixel routine
- rts ; leave
-
- continue:
- move.w vblanks,d0 ; get the vblanks counter value
- addq.w #1,d0 ; increment the counter
- move.w d0,vblanks ; store the vblanks counter value
- cmpi.w #32000,d0 ; see if the appropriate time has passed
- bne gohome ; otherwise skip it
-
- move.l newscreen,d0 ; get the screen address
- movea.l d0,a0 ; move the newscreen address into a0
- move.w #0,d0 ; set the loop counter to zero
-
- clearit:
- move.l #0,(a0)+ ; clear the screen
- addq.w #1,d0 ; increment loop counter
- cmpi #8000,d0 ; have 8000 longs been cleared?
- bne clearit ; otherwise do some more
-
- movea.l #$44e,a0 ; set to _v_bas_ad - contains the screen address
- move.l (a0),oldscreen ; get the old screen location
-
- movea.l #$ffff8201,a0 ; set to the Physbase location
- movea.l #newscreen,a1 ; move the address of newscreen into a1
- adda.l #1,a1 ; increment the pointer to get correct byte
- move.b (a1),(a0) ; move the byte to the Physbase location
- adda.l #2,a0 ; increment to the other byte location
- adda.l #1,a1 ; add 1 to get the correct byte of newscreen
- move.b (a1),(a0) ; move the second byte
-
- movea.l #$ff8260,a0 ; set to ff8260 - contains the resolution
- move.b (a0),d0 ; put resolution in d0
- andi.w #$0003,d0 ; mask off any rubish
- move.w d0,rez ; store it in 'rez'
- move.w #0,oldrez ; store '0' in oldrez
-
- cmpi.w #1,d0 ; see if we are in medium resolution
- bne dontchange ; if not, don't attempt to change res
- movea.l #$ff8260,a0 ; set to the hardware resolution location
- move.w (a0),d1 ; get the old resolution value
- move.w d1,oldrez ; save it
- move.w #0,d0 ; move a zero into d0
- movea.l #$44c,a0 ; set to the system variable location
- move.b d0,(a0) ; store the new res
- movea.l #$ff8260,a0 ; set to the hardware location
- move.b d0,(a0) ; store the new res
- move.w d0,rez ; store the new res in 'rez'
-
- dontchange:
- cmpi.w #0,d0 ; assign resolution dependant values
- bne notlow
- move.w #8,wordbytes ; bytes per 16 screen pixels
- move.w #$000f,colormask; number of colors to be used
- move.w #80,onethird ; horizontal distance (c. one third of screen)
- move.w #40,fromleft ; value to start from left of screen
- move.w #1,xadjust ; x factor
- bra gotrez
-
- notlow:
- move.w #2,wordbytes ; bytes per 16 screen pixels
- move.w #0,colormask ; number of colors to be used
- move.w #160,onethird ; horizontal distance (c. one third of screen)
- move.w #40,fromleft ; value to start from left of screen
- move.w #2,xadjust ; x factor
-
- gotrez:
- movea.l #oldpalette,a1 ; set destination of palette copy
- movea.l #$ff8240,a0 ; set source of palette copy
- jsr getsetpalette ; jump and do the copy
- movea.l #newpalette,a0 ; set source of palette copy
- movea.l #$ff8240,a1 ; set destination of palette copy
- jsr getsetpalette ; jump and do the copy
-
- move.w #1,vbiflag
-
- move.w #0,countfw ; zero the counter
- move.w #0,d7
- move.w #0,fnum
- move.w #0,numcount
-
- four_fw:
- movea.l #$4bc,a0 ; pointer to system clock
- move.w (a0),d0 ; get the value
- move.w colormask,d1
- and.w d1,d0 ; mask to use maximum colors only
- cmpi.w #0,d0
- bne nzero3
- ori.w #1,d0 ; insure plane one
- nzero3:
- move.w d0,fcolor ; store in fcolor
-
- move.w d7,d4
- addq.w #1,d4
- mulu #10,d4
- addi.w #40,d4
- move.w d4,fheight ; store in fheight
-
- move.w (a0),d4 ; get another random number
- andi.w #3,d4 ; and it to assure value is in range
- addq.w #1,d4 ; add one
- move.w d4,numexplode ; store the value
-
- move.w d7,d4
- move.w d4,trajectory ; store in trajectory
- mulu onethird,d4 ; adjust the starting point
- add.w fromleft,d4 ; according to resolution
-
- move.w #199,ty ; store the y coordinate starting point
- move.w #199,d1 ; put 199 in d1
- move.w d4,tx ; store the x coordinate starting point
- move.w d4,d2 ; store x value
-
- move.w countfw,d7
-
- addq.w #1,d7
- move.w d7,countfw
- cmpi.w #1,d7
- bne pastfw1
- movea.l #fcolor,a0
- movea.l #fw1,a1
- jsr assign
- move.w fcolor,d0
- move.w ty,d1
- move.w tx,d2
- jsr pixel ; make the pixel
- bra four_fw
-
- * Generate four sets of random firework data
-
- pastfw1:
- cmpi.w #2,d7
- bne pastfw2
- movea.l #fcolor,a0
- movea.l #fw2,a1
- jsr assign
- move.w fcolor,d0
- move.w ty,d1
- move.w tx,d2
- jsr pixel ; make the pixel
- bra four_fw
- pastfw2:
- cmpi.w #3,d7
- bne pastfw3
- movea.l #fcolor,a0
- movea.l #fw3,a1
- jsr assign
- move.w fcolor,d0
- move.w ty,d1
- move.w tx,d2
- jsr pixel ; make the pixel
- bra four_fw
- pastfw3:
- cmpi.w #4,d7
- bne gohome
- movea.l #fcolor,a0
- movea.l #fw4,a1
- jsr assign
- move.w fcolor,d0
- move.w ty,d1
- move.w tx,d2
- jsr pixel ; make the pixel
-
- gohome: rts ; leave
-
-
-
- **********************************************************************
- * Here is the keyboard patch *
- **********************************************************************
-
- trapper:
- move.w #0,vblanks ; reset the vbi counter to zero
- movem.l a0-a1/d0/d7,-(sp) ; save addresses and loop counter
- move.w vbiflag,d0 ; get the value in the vbi flag
- cmpi.w #1,d0 ; see if it is one (enabled)
- bne getlost ; if not leave...
-
- movea.l #$ffff8201,a0
- movea.l #oldscreen,a1
- adda.l #1,a1
- move.b (a1),(a0)
- adda.l #2,a0
- adda.l #1,a1
- move.b (a1),(a0)
-
- move.w #0,fnum ; zero fnum in case of fireworks going off
-
- movea.l #$ff8240,a1 ; set destination of palette copy
- movea.l #oldpalette,a0 ; set source of palette copy
- jsr getsetpalette ; jump and do the copy
-
- move.w #0, vbiflag ; set the vbi flag to zero
-
- move.w oldrez,d0
- cmpi.w #0,d0
- beq getlost
- move.w #1,d0
- movea.l #$44c,a0
- move.b d0,(a0)
- movea.l #$ff8260,a0
- move.b d0,(a0)
-
- getlost:
- movem.l (sp)+,a0-a1/d0/d7 ; restore addresses and loop counter
- insert:
- jmp $11111111 ; this address is changed upon program init
-
-
- **********************************************************************
- * This routine XORs a pixel on the screen *
- **********************************************************************
-
- pixel:
-
- * Pixel color in d0
- * y coordinate in d1
- * x coordinate in d2
- * use a3 for screen address
- * use a4 for bit mask
-
- movea.l newscreen,a3 ; put the screen address in a3
- mulu #160,d1 ; multiply the y coordinate by 16
- andi.l #$0000ffff,d1
- adda.l d1,a3 ; add the y value to a3
- andi.l #$0000ffff,d2
- divu #16,d2 ; divide the x by 16 to get the number of words
- move.l d2,d1 ; store the result in order to ascertain the remainder
- andi.l #$0000ffff,d2
- mulu wordbytes,d2 ; multiply by wordbytes to find the correct byte offset
- andi.l #$0000ffff,d2
- adda.l d2,a3 ; add the byte offset to a3
- lsr.l #8,d1 ; shift 8
- lsr.l #7,d1 ; shift 7
- andi.l #$000000fe,d1 ; offset in d1
-
- movea.l #pixbits,a4 ; put the pixbit address in a4
- adda.w d1,a4 ; add the correct offset to a4
- move.w (a4),d3 ; move the data into d3
-
- * Now the pixel data is in d3 and the screen address is in a3
-
- btst #0,d0
- beq secondplane ; if not, skip to the second plane
-
- move.w (a3),d2 ; get the screen byte
- eor.w d3,d2 ; XOR it with the data
- move.w d2,(a3) ; put it back on the screen
-
- secondplane:
- adda.w #2,a3 ; add the correct number of bytes
- btst #1,d0
- beq thirdplane ; if not, skip to third plane
-
- move.w (a3),d2 ; get the screen byte
- eor.w d3,d2 ; XOR it with the data
- move.w d2,(a3) ; put it back on the screen
-
- thirdplane:
- adda.w #2,a3 ; add the correct number of bytes
- btst #2,d0
- beq fourthplane ; if not, skip to the fourth plane
-
- move.w (a3),d2 ; get the screen byte
- eor.w d3,d2 ; XOR it with the data
- move.w d2,(a3) ; put it back on the screen
-
- fourthplane:
- btst #3,d0
- beq lastplane ; if not then leave
-
- adda.w #2,a3 ; add the correct number of bytes
- move.w (a3),d2 ; get the screen byte
- eor.w d3,d2 ; XOR it with the data
- move.w d2,(a3) ; put it back on the screen
-
- lastplane:
- rts ; leave the routine
-
-
- *************************************************************************
- * Get/Set current pallete (must be in Supervisor) *
- *************************************************************************
-
- getsetpalette:
- move.w #0,d7 ; zero the counter
-
- gsploop:move.w (a0)+,(a1)+ ; move the data
- addq.w #1,d7 ; increment the counter
- cmpi.w #16,d7 ; have you copied 16?
- bne gsploop ; if not, do some more
-
- rts ; leave subroutine
-
- ************************************************************************
- * Draw a firework explosion part *
- ************************************************************************
-
- drawfw:
- move.w fcolor,d0 ; get the firework color
- move.w #0,d7 ; zero the counter
- movea.l #fpattern,a5 ; get the address of fpattern
- move.w fnum,d6 ; load the firework number
- move.w d6,d5 ; save the firework number in d5 for future use
- mulu #3,d6 ; figure out the radius
-
- do_dots:
- move.w tx,d2 ; get the x coordinate
- sub.w d6,d2 ; adjust to top left of firework pattern
- move.w xadjust,d4 ; load xadjust
- cmpi.w #2,d4 ; see if it is 2
- bne xa_not_2 ; go on otherwise
- sub.w d6,d2 ; adjust additional amount
- xa_not_2:
- move.w ty,d1 ; get the y coordinate
- sub.w d6,d1 ; adjust to top left of firework pattern
- move.w (a5)+,d4 ; get the x pattern element
- mulu d5,d4 ; multiply according to the size of the fw
- mulu xadjust,d4 ; resolution factor
- add.w d4,d2 ; add the x position to the top left of pattern
- move.w (a5)+,d4 ; get the y pattern element
- mulu d5,d4 ; multiply according to the size of the fw
- add.w d4,d1 ; add the y position to the top left of pattern
- addq.w #1,d7 ; increment the counter
- jsr pixel ; now, make the pixel
- cmpi.w #8,d7 ; see if you have done the 8 dots
- bne do_dots ; do some more if not
-
- rts ; leave the routine
-
- ************************************************************************
- * Move the specified firework data to the work area *
- ************************************************************************
-
- assign:
- move.w #0,d0
-
- do_more:
- move.w (a0)+,(a1)+
- addq.w #1,d0
- cmpi.w #10,d0
- bne do_more
-
- rts
-
-
- **********************************************************************
- * Data Storage Segment *
- **********************************************************************
-
- .even
- .data
-
- pixbits: .dc.w $8000,$4000,$2000,$1000,$0800,$0400,$0200,$0100
- .dc.w $0080,$0040,$0020,$0010,$0008,$0004,$0002,$0001
-
- newpalette: .dc.w $0000,$0070,$0700,$0700,$0770,$0707,$0077,$0777
- .dc.w $0770,$0704,$0074,$0740,$0704,$0740,$0400,$0700
-
- fpattern: .dc.w $0000,$0003,$0001,$0001,$0003,$0000,$0005,$0001
- .dc.w $0006,$0003,$0005,$0005,$0003,$0006,$0001,$0005
-
- fw1: .dc.w $0000,$0000,$0000,$0000,$0000,$0000
- .dc.w $0000,$0000,$0000,$0000
- fw2: .dc.w $0000,$0000,$0000,$0000,$0000,$0000
- .dc.w $0000,$0000,$0000,$0000
- fw3: .dc.w $0000,$0000,$0000,$0000,$0000,$0000
- .dc.w $0000,$0000,$0000,$0000
- fw4: .dc.w $0000,$0000,$0000,$0000,$0000,$0000
- .dc.w $0000,$0000,$0000,$0000
-
-
- **************************************************************************
- * Block Storage Segment
-
- .bss
-
- rez: .ds.w 1 ; current resolution
- oldrez: .ds.w 1
- oldscreen: .ds.l 1 ; old screen pointer
- keyvector: .ds.l 1 ; keyboard vector
- oldpalette: .ds.w 16
- wordbytes: .ds.w 1 ; bytes per screen word
- colormask: .ds.w 1
- onethird: .ds.w 1
- fromleft: .ds.w 1
- xadjust: .ds.w 1
- newmem: .ds.l 8200
- newscreen: .ds.l 1
- vblanks: .ds.w 1 ; vblank counter
- countfw: .ds.w 1
- vbiflag: .ds.w 1 ; status of the screen saver
- ; 0=not enabled
- ; 1=enabled
-
- fcolor: .ds.w 1
- numexplode: .ds.w 1
- trajectory: .ds.w 1
- fheight: .ds.w 1
- ty: .ds.w 1
- tx: .ds.w 1
- fnum: .ds.w 1
- numcount: .ds.w 1
- fwvblanks: .ds.w 1
-
-
- .ds.l 255 ; the stack can grow down 1K before
- ustk: .ds.l 1 ; it starts to eat the program!!
- .end
- əəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəəə