Contact me | Login | Search | Sitemap | Site Notice

XMAS-Demo 2019 in 6502-Assembler

Introduction

How would an Apple-][-Christmas look like without some new software for this great machine? 8-Bit-Shack decided to produce another XMAS-Demo in order to celebrate this year's holiday season!

What would we normally expect here deep in the Ore Mountains of Germany? Yes, snow - and lots of it! And of course we have Santa Claus here!

So here we go...


Key Features:

  • Apple ][ Christmas Demo using 40 column text mode and HIRES graphics with MockingBoard sound.
  • Featuring some text mode tricks and HIRES graphics animation with sound:

    • Animated Santa Claus with his reindeer sled
    • Random background image generation (mountains & trees)
    • Christmas greeting message
    • Loads of snow with snowfall state machine (particle simulator)
    • Animated HIRES bottom text scroller synchronized with the MockingBoard timer
    • Music playback via a MockingBoard (or compatible sound card)

  • Most features of the demo are controlled via pseudo random number generators (PRNG) with random seed number generation via a RDKEY-honeypot.

Download:

  • Download the DSK-image (Apple //e enhanced or better only!)!
  • Download an Apple ][+ friendly DSK-image (Apple ][+ or //e with 6502 and 64k RAM)
  • Do you want unlimited snow? Download this DSK-image and press "S" during the snowfall in order to toggle between "limited" and "unlimited" snowfall!

Keyboard Commands:

  • <P>: Pause/Resume music
  • <Q>: Quit the main part
  • <S>: toggle between unlimited and limited snowfall (only available in the special version - see above)

Credits:

  • Code & Gfx: SingleMalt
  • Music: CJ Splinter
  • Additional Animation: Dr. N. H. Cham

 System Requirements:

  • Apple ][+ (or better, optimized version for //e enhanced or better available)
  • 65C02 CPU (Apple ][-friendly version requires only 6502 CPU)
  • 48 kB RAM (Apple ][-friendly version requires 64k RAM)
  • MockingBoard (optional: no scroll text and music without MockingBoard!)

Acknowledgements:

This demo would not have reached its current point of progress without the help and software of other great guys out there. Thank you for your great software and support!

I want to point out some major contributors to this demo:

Feature Video - Assembly Lines Podcast

The XMAS-Demo 2019 was featured in the #108 Assembly Lines Podcast by its host Chris Torrence:


Behind the Screens - Tech Notes

Intro

  • The Intro uses the standard 40-column text display
  • The user can "choose" feature sets. However, the user input generated here is only used to seed the multiple pseudo random number generators in the demo.
  • The RDKEY monitor routine inlcudes a 16-bit counter that increases memory locations $4E and $4F of the zero page while waiting for the keypress. This counter value is used as a random seed number for the PRNGs.
Intro screen on the XMAS-Demo 2019 with keypress honeypot for seeding the pseudo random number generator.

Main Part

  • The main part uses HIRES page 1 for all graphic displays. Sorry this time no double buffering here!

Mountains & Trees

  • For generating the mountain landscape a pseudo random number generator is used. Using a random seed value from the RDKEY-routine before, the algorithm can produce 256 different landscapes.
  • For rendering the mountains a sine function is superimposed with a cosine function. The base frequency of both functions is varied by generated random numbers using the random seed values. This results in a mostly smooth mountain slope.
  • The trees are generated using a small coordinate table with a fixed X-coordinate. The Y-coordinate is automatically adapted to the generated mountain height.
  • For drawing the mountains and the trees the demo uses the AppleSoft HPLOT ROM-routine. Since drawing the landscape is not a time critical task the rather slow line drawing algorithm in ROM is used which saves a lot of RAM space since there is no need to implement an own line drawing Bresenham algorithm.
  • As you might have noticed the upper limit of the mountains is limited by a white line. This line is needed later for the snowfall algorithm as a limit for the falling snow.
One of the randomly generated mountain patterns with attached trees.
One of the randomly generated mountain patterns with attached trees.
One of the randomly generated mountain patterns with attached trees.

Snowfall

  • Snowfall is simulated by 256 single pixels fluttering from the top of the screen onto the mountain landscape with trees.
  • For initializing the snowfall the random seed numbers acquired by the RDKEY-routine are also used resulting in different snowfall patterns.
  • Snowfall starts slowly and increases in the meantime until reaching a full animation of 256 single flakes.
  • A snowflake can fall downwards and additionally to the right or the left. Each movement direction is chosen via the pseudo random number generators. Since the PRNGs yield evenly distributed random numbers the movement of the flakes is mainly downwards with small jittering on the X-axis.
  • In order to check if a snowflake has hit the ground or a tree the demo contains a special (H)SCRN-function that checks if a certain pixel is set or not.
  • Each snowflake has a certain amount of movement energy which means that a flake can roll down slopes or move horizontally a bit when hitting the ground. This yields different pile up patterns on the ground.
  • As you might have noticed the total number of snowflakes that are finally residing on the ground is limited. The limit is set to 6144 flakes (24 * 256). Why that number? I just thought that it looks nice!

Santa with Sled

  • After a while of the snowfall animation Santa is crossing the scene with his sled. First to the right, than to the left and so on.
  • Santa is a bitmap which is seven bytes wide and 17 lines high.
  • Each animation step is precalculated at the beginning of the algorithm. The bitmap is contained only one time in the code. The necessary shifts of the bitmap for doing the sled movement are all done before the animation starts. So the algorithm works with 7 bitmaps for each movement direction.
  • The algorithm contains HIRES shift routines, so it is not necessary to enter all different Santa bitmaps byhand. The sled flying to the right is generated out of a single bitmap which is shifted to the right by two pixels for each frame.
  • Since the algorithm also contains a HIRES flip routine we can generate the sled bitmaps flying to the left out of a single bitmap sled flying to the right.

Animated Santa

  • The shifted bitmaps only display a static Santain the beginning. This leads to a short and sudden interruption of the demo after two sled rounds.
  • A small patch-routine overwrites some bytes of the shifted Santa bitmaps resaulting in a nice animation of the reindeer legs and the Santa's hat. This detail adds more spice to the animation.

Christmas Greeting

  • After a certain amount of snowflakes have been placed on the ground a Christmas greeting logo is copied onto the HIRES screen.
  • The logo is stored as linear uncompressed data stream in higher RAM and just copied to the HIRES page.
  • The snowfall algorithm recognizes the logo depositing the snow on the logo until the maximum number of snowflakes has been reached.
  • Santa and his sled is still busy crossing the screen, however, the Y-coordinate of his trajectory is now fixed.

Outro

  • Pressing "Q" leaves the main part of the demo and starts the outtro-sequence
  • This sequence consist of a simple text animation with main credits and a marquee effect while waiting for a keypress.
  • The closing sequence is a CRT mimicking effect just clearing the whole text screen.

Behind the Screens - Algorithmic Details

Basic Considerations

This demo was born during a long chat with my friend Dr. Cham. He was working on some small Turbo Pascal code examples to give to his students as programming tasks when I got attracted to a little snowfall demo for VGA video modes and I was asking myself if it would be possible to make an Apple ][ version?!

Simulating a snowfall is mainly keeping track of an array of snow flake coordinates and states. As a simple approach I was testing an array of 256 snowflakes on the screen and from my point of view it looked good enough so I stayed with that limited number of active flakes.

The simple task was undrawing and drawing the single flakes and implementing a pseudo random number generaor routine that scatters the flakes nicely on the screen in X- and Y-direction. Another simple task was the state machine that "decides" upon the direction of movement of a flake. Since the number sequence of a pseudo random number generator using a linear shift register are evenly distributed and drawing only 0, 1 and 2 as random numbers using "0" for a movement to the left & down, a "1" for a movement only downwards and a "2" for a movement to the right and down in total the snowflakes are falling "straight" to the ground.

I also experimented with drawing numbers from other ranges simulating a diagonal snowfall e.g. like there is a wind blowing from the side. However, from my point of view the strraight snowfall with a bit of floundering looked best.

What was way more difficult was the development of a HIRES SCRN-function like it is well known from AppleSoft-Basic resulting the color of a screen pixel of the GR-screen for a given X-Y-coordinate pair. This function is important in order to decide if a snowflake hits the ground or a tree.

There are some solutions available on the internet but they all are quite slow or inaccurate. So the biggest effort was to develop a HIRES SCRN-function that is fast enough for a smooth animation of 256 single snowflakes!

The following code snippet shows the fast HIRES SCRN-function checking three pixel positions: down & left, down, down & right for set pixels. The return values are stored in LFREE, DFREE and RFREE and are evaluated in the snowfall state machine:

; 
; check if pixel is set
;	
FHSCRN     		
        LDX YPOS			; ypos of pixel to check
	LDA YLOOKLO,X
        STA HBASL
        LDA YLOOKHI,X
        ORA G_PAGE
        STA HBASL+1

	LDX XPOSL			; xpos of pixel to check
	DEX				; left & down position
	LDY DIV7LO,X
        LDA MOD7LO,X
	TAX
        LDA ANDMASK,X
        AND #%01111111
        STA ANDMSK	       		          		
        LDA (HBASL),Y			; get HIRES-byte
        AND ANDMSK			; check if pixel is set
	STA LFREE			; if 0 pixel is NOT set
				
	LDX XPOSL			; xpos of pixel to check
	LDY DIV7LO,X			; check downwards
        LDA MOD7LO,X
	TAX
        LDA ANDMASK,X
        AND #%01111111
        STA ANDMSK	       		          		
        LDA (HBASL),Y			; get HIRES-byte
        AND ANDMSK			; check if pixel is set
	STA DFREE			; if 0 pixel is NOT set

	LDX XPOSL			; xpos of pixel to check
	INX				; right & down position
	LDY DIV7LO,X
	LDA MOD7LO,X
	TAX
	LDA ANDMASK,X
	AND #%01111111
	STA ANDMSK	       		          		
	LDA (HBASL),Y			; get HIRES-byte
	AND ANDMSK			; check if pixel is set
	STA RFREE			; if 0 pixel is NOT set
	RTS	

Santa Generator

After the snowfall algorithm was working Dr. Cham came up with an idea to let Santa Claus play a role in the demo. The idea to let Santa fly through the scene with a small sled was born and so I started to make drawing with pencil and paper in order to design something sled-like.

You might recall the odd HIRES memory layout (7 pixels per byte, odd and even screen baytes when you need to consider appropriate coloring etc.) of the Apple ][. Hence moving a bitmap over the screen at a nice speed normally requires preshifted bitmaps - to be clear: seven bitmaps where every bitmap needs to be shifted two pixels in the desired direction.

Preshifting is mostly done in the development phase using pencil & paper or tools and implementing the results directly in the code as a table. As I am somewhat a lazy butt I decided to write and algorithm that starts with a single bitmap and does the following:

  • Automatically shift a bitmap to the right generating the required 7 bitmaps for a smooth animation in one direction
  • Flip a bitmap horizontally
  • Automatically shift the flipped bitmap to the left in order to generate the other 7 bitmaps for a smooth animation to the left

After some fiddling and bit twiddling the demo now contains routines that are able to shift & flip arbitrary bitmaps. Every starts with a single bitmap with the following layout (7 columns, 17 rows, the first column was intentionally set to $0):

SLED1
DFB %00000000,%10000000,%10001010,%10000000,%10000000,%10000000,%10000000
DFB %00000000,%10000000,%11101010,%10000000,%10000000,%10000000,%10000000
DFB %00000000,%11000000,%11111010,%10000000,%10000000,%10000000,%10000000
DFB %00000000,%10110000,%11111010,%10000000,%10000000,%10000000,%10000000
DFB %00000000,%10000000,%10101010,%10000001,%10000000,%10110000,%11100000
DFB %00000000,%10000000,%10101010,%10000010,%10000000,%11000000,%10011001
DFB %00000000,%11000000,%10001010,%10001000,%10000000,%10000000,%10000110
DFB %00000000,%11000000,%10001010,%10100000,%11010101,%10001010,%10101000
DFB %00000000,%10000000,%10001010,%10000000,%10000000,%10100000,%10101001
DFB %00000000,%10000011,%10001010,%10000000,%10000000,%10000000,%10010100
DFB %00000000,%11111111,%10001111,%10000000,%10000000,%11000101,%10001010
DFB %00000000,%11010111,%10001111,%10000000,%10000000,%11010101,%10000010
DFB %00000000,%11010111,%11111010,%10000011,%10100000,%11010101,%10000000
DFB %00000000,%11011100,%10101010,%10001111,%10100000,%11010001,%10000010
DFB %00000000,%11111100,%11111111,%10110011,%10001000,%11000000,%10000000
DFB %00000000,%10110000,%11100000,%10110000,%10101000,%11000000,%10000000
DFB %00000000,%11111111,%11111111,%10001111,%10000000,%10010000,%10000000

Shifting a bitmap to the right for two pixels requires two operations:

  • Shifting the bits of a HIRES screen byte two bits to the left using two ASL operations.
  • Considering the two leftmost bits that are shifted out of the byte and need to be transferred to the neighboring HIRES screen byte. This can be done by four ROL operations.

In order to speed things up - which is not really necessary in this demo since the SLED-arrays are only setup once during the initialization phase of the demo - we can use some lookup tables which do the ASL/ROL-magic for us. The lookup tables are set up as follows:

;
; table 3: 2 x ASL of a byte
;
	LDX #0				; HIRES byte shift tables 
lpLUT3	TXA				; shift two pixels to the right
	ASL
	ASL
	AND #%01111111			; strip-off HI-bit
	STA TAB3,X
	INX
	BNE lpLUT3
						
; table 4: 4 x ROL & AND #%00000011 of a byte
; making the OR-mask for the shifted two bits

	LDX #0
lpLUT4	TXA
	ROL				; shift them in order to fit 
	ROL				; in the former byte
	ROL
	ROL
	AND #%00000011			; get only the first two bits
	STA TAB4,X
	INX
	BNE lpLUT4

Shifting a bitmap to the left requires the opposite operations using LSR/ROR-operations. This is also done using two fast lookup tables.

To be continued...