Learn Multi platform 6502 Assembly Programming... For Monsters!

Super Simple Series

In this series we'll take a look at a variety of basic tasks that you may need to look at when you're starting out with programming these classic systems...

In each case the source-code will be a single file with no Includes to make things easy if you're using a different assembler (though some may include a binary.)


Lesson S19 - Keypad Reading on the Commodore PET!
Let's use the keyboard to move a simple character block 'sprite' around the screen of the Commodore Pet!

PET_keys.asm

Defining Parameters, and drawing sprites

First we're going to need some zero page bytes to define an X,Y position.

Our 'sprites' will have 2 frames of animation (stored in FrameNo), and we'll use different 'pairs' for Up+Down, Left and Right (Stored in FrameBase)
We're going to need to define some frames of animation for our test. Each frame is 4x4 characters (8x8 pixels).

There are two frames per direction, with 3 directions (Up and Down use the same sprite)
These were created with my AkuSprite editor!
Given a 'Sprite number' we need to multiply this by 16 to get the offset for the sprite. (each sprite is 4x4, 16 bytes)

We use GetVDPScreenPos to calculate a VRAM address from the X,Y co-ordinate, and GetNextLine to move down one VRAM line.

We copy all the bytes from the sprite source z_hl to the VRAM destination z_de


BlankPlayer is an alternate version which removes the sprite from the screen.
GetVDPScreenPos calculates the VRAM address of the screen position specified by X,Y registers, in Zero page entries z_d+Z_e

The screen base is $8000 in ram, and each line is 40 bytes, so our formula is:
VRAM= $8000 + Ypos *40 + Xpos

As it's hard to multiply by 40, we multiply Ypos by 8 and 32, and add the two together!
To move down a line, we add 40 to the current VRAM position
This works fine on the standard 40 character screen.

If you're using 80 character wide screen modes, you'll need alter the formula!

Reading the Keyboard

To read a line of the keyboard, we first write the line number to memory mapped port $E810,

We then read a byte from $E812 - each bit will be a different key -
A 0 means the key is pressed.
A 1 means the key is not pressed.

We test each cursor key, and Space and Enter (we can use these as fires)


Our test program

We're going to define the starting position of our character - z_h will store our joystick buttons - we initialize this to zero - as we need to run the main loop but don't want to cause any keypresses.
Next comes the joystick reading routine - we skip this the first run

We read in from the joystick into z_H - until a key is pressed we'll wait in an infinite loop... when it is pressed we start our drawing routine...

First we clear the old player sprite from the screen.
We test each of the bits in z_h (which was returned from the joystick routine)

In each case, if the bit is 0 then the button isn't down - and we skip over the routine to move the character's X or Y position

Before moving we check if we're already at the 'limit' of the screen - we don't want to go over the edges, so we skip moving if we are already at the edge.
We save the new XY position.

We then 'flip' the frame (0 and 1)... this gives a 'walking' animation.

We then draw the new player position... wait a while and repeat.
Here is the result!


Lesson S20 - Sprite Clipping on the BBC
We've looked before at drawing a bitmap to the screen, but there's a challenge!
For many games we'll need to be able to draw sprites that are 'partially off' the screen, We'll clip off the offscreen part.
Lets look at the upgraded code.

BBC_Bitmap_Clipping.asm


Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.

We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data
at the start of our drawing routine we need to calculate the VRAM destination of the sprite,

We multiply the 'Width' by 8, to match the X offset of the sprite - this is because there's 8 lines 'between' each horizontal byte in VRAM
Unlike our previous bitmap example, Our Sprite drawing routine does each horizontal line one at a time, not 8x8 blocks, this means we add 8 to the VRAM address after each byte.

We repeat for the width of the sprite.
After each line, we need to move down the VRAM address one line, what we need to do to achieve this depends on the line.

for the first 7 lines we just add $0001, but after 8 lines we need to add $0200
After each line, we may need to 'skip over' any clipped bytes of our source bitmap to get to the next line.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines)

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return


Lesson S21 - Sprite Clipping on the C64
We've looked before at drawing a bitmap to the screen, but we need to do better!
For many games we'll need to be able to draw sprites that are 'partially off' the screen, We'll clip off the offscreen part.
Lets look at the upgraded code.

C64_Bitmap_Clipping.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

on the C64, we're using the larger screen size of 160x200... We're also using 4 color mode and narrower tiles of 4x8

On the C64,The logical units are still based on the principle a single tile is 4x4 logical units.

Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data
at the start of our drawing routine we need to calculate the VRAM destination of the sprite,

We multiply the 'Width' by 8, to match the X offset of the sprite - this is because there's 8 lines 'between' each horizontal byte in VRAM
Unlike our previous bitmap example, Our Sprite drawing routine does each horizontal line one at a time, not 4x8 blocks, this means we add 8 to the VRAM address after each byte.

We repeat for the width of the sprite.
After each line, we need to move down the VRAM address one line, what we need to do to achieve this depends on the line.

for the first 7 lines we just add $0001, but after 8 lines we need to add $0140
After each line, we may need to 'skip over' any clipped bytes of our source bitmap to get to the next line.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines)

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return


Lesson S22 - Sprite Clipping on the VIC-20
We looked last before at using custom characters to draw a bitmap 'sprite' on the screen.

This time we'll extend the example, and add the ability to 'clip' the sprite so it can partially go offscreen.

VIC_Clipping_Rom.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

The VIC 20 can't do our ideal 256x192... it's 22*23 tile screen gives us an effective 'Logical' resolution of 88*96 units

Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

on the Vic we have two versions of this code...
DrawPlayer shows the Chibiko graphic,
BlankPlayer removes it.

If there is nothing onscreen, 'DoCrop' will return the Carry set.

If there's something to draw, we'll start by calculating the Vram destination position.
We transfer the tiles that make up our character to VRAM at z_de ($1E00+)... we also set the matching colors in color ram at $9600+

We repeat for the full width of the line, however after each line, if the sprite is horizontally cropped, we need to remove 'spritehclip' tiles.

We then repeat for the other remaining lines.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

We have to mask using "and #%11111100" to compensate for the fact this system can only work in 8x8 pixel tiles (4 logical units)

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines)

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return



Lesson S23 -Sprite Clipping on the Atari 800 / 5200
Lets port our sprite clipping routine to the Atari systems, We'll 'upgrade' our previous sprite routine, so it can crop the sprites so they are partially offscreen.

A52_Bitmap_Clipping.asm


Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

We're going to use 4 colors on the Atari 800/5200... which means we'll use a screen resolution of 160x192 pixels, and a logical resolution of 160x96... meaning our tiles are 4x8 pixels on this system, not 8x8 like most.

Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

DrawPlayer shows the Chibiko graphic using XOR

If there is nothing onscreen, 'DoCrop' will return the Carry set.
If there's something to draw, we'll start by calculating the Vram destination position.
We transfer bitmap data from the source address in zero page pair z_iy.

We XOR this with the screen data at z_de.

We repeat this for all the bytes of the line, we then need to move down a line, and maybe crop the source data
After each line we need to move the VRAM destination down one line - each line is 40 bytes
We need to update the source bitmap byte... we do this by adding Y to the source address z_iy
If we had to crop the left or right hand side of the sprite, we will need to skip some bytes before the next line of the source bitmap.

We do this now.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines)

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return

Lesson S24 - Sprite Clipping on the Apple II
The Apple II screen is kind of Black and white - and Kind of color!... depending on the combination... lets learn what it all means, and get a smiley onscreen!

AP2_Bitmap_Clipping.asm


Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

The Apple II screen is weird! each byte stores 7 pixels and one color bit! for this reason although our tile is 4x4 logical units, but this will represent a physical 7x8 pixel bitmap tile.

We'll only crop horizontally in byte increments anyway.


Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

DrawPlayer shows the Chibiko graphic using XOR

If there is nothing onscreen, 'DoCrop' will return the Carry set.
If there's something to draw, we'll start by calculating the Vram destination position.
We transfer bitmap data from the source address in zero page pair z_iy.

We XOR this with the screen data at z_de.

We repeat this for all the bytes of the line, we then need to move down a line, and maybe crop the source data
After each line we need to move the VRAM destination down one line... unfortunately on the Apple II this is a little tricky!

Depending on the bits of our Y line, how we need to adjust our Vram pos will vary.
The address of the line is calculated from the following bits %AABBBCCC - AA*$0028  BBB*$0080  CCC*$0400       

In this part of the code, the Low byte z_E will be stored in Y, and the High byte z_D will be stored in X.

To move down a line, first we inc the CCC part, by adding $04 to the high byte of the VRAM address.

If that overflows, we need to update the BBB part, which uses bit 7 of the low byte, and bits 0,1 of the High byte of the VRAM address

If that overflows we need to update the AA part, by adding $28 to the low byte of the Low byte of the VRAM address
We need to update the source bitmap byte... we do this by adding Y to the source address z_iy
If we had to crop the left or right hand side of the sprite, we will need to skip some bytes before the next line of the source bitmap.

We do this now.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines)

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return


Lesson S25 - Sprite Clipping on the Atari Lynx
We drew a sprite to the screen before, now lets upgrade it with some sprite clipping.

LNX_Bitmap_Clipping.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.

We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


The joystick and sprite routines used here are based on those in the simple series, but a few changes will be needed.
The sprite routine will have 'clipping' and is likely to be slower than the unclipped version, so if your sprite can't go offscreen this may not be the best option.

The LYNX screen is pretty small!... we'll only have screen space for a logical screen of 80x51 units

Of course, this smaller logical visible screen will still be centered in a larger 256x256 logical screen


Our Sprite Routine

Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

If there is nothing onscreen, 'DoCrop' will return the Carry set.
If there's something to draw, we'll start by calculating the Vram destination position.
We transfer bitmap data from the source address in zero page pair z_iy.

We XOR this with the screen data at z_de.

We repeat this for all the bytes of the line
After each line we need to do 3 things.

1. increase z_IY by the number of bytes we drew to the screen

2. add any 'skipped' horizontal bytes to z_IY which are missed due to cropping

3. add $50 bytes to the VRAM destination to move down 1 line.

We then repeat for the next line of our sprite


Page flipping

To avoid any pesky flicker, we're using 2 memory addresses for screen drawing... $B800 and $D800

We draw to one, and show the other... then flip them over - this means the viewer never sees the drawing screen.
Before the next draw we clear the screen...

the screen is $2000 bytes in size (Well.. actually $1FE0) so we write zeros to all these based on our current 'ScreenBuffer' address.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to physical units (Horizontal bytes and vertical lines).

There's 2 pixels per logical unit, and 2 per horizontal byte, so no corrections are needed on the X axis for the Lynx, but the Y axis needs doubling.

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return


Lesson S26 -  Tile Bitmap Clipping on the NES
We drew our 'Chibiko' mascot on the NES using the tilemap before, this time we'll improve the code, allowing the image to be clipped.

Lets have a go!

NES_Bitmap_Clipping.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


Our logical units are in 2x2 pixel blocks, but our tiles are 8x8 pixels, therefore we can only draw movements of our graphics in 4x4 logical unit 'jumps'

Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the first tile pattern

If there is nothing onscreen, 'DoCrop' will return the Carry set.
We don't actually write to the tilemap, we write to a cache of changes that will be written during the next vblank

GetVDPScreenPos calculates and writes the address of the tile to change, writing it in the tilemap.

We then write the new tile number... we repeat this for each line of the tilemap

After a line of the tilemap, we update the source tile number to compensate for any clipping with "NoSpriteClip"
When we want to change a tile, we calculate the address of the tile we want to change in VRAM, we write the HL pair of the destination address into the VDPBuffer, a third byte needs to be written to tell the NMI what tile to set.

We can only set a total of 32 tiles per NMI in this way, so if there are already 32*3 bytes in the buffer we wait for the VBlank
The NMI interrupt handler transfers all the tiles to change during VBLANK.

The count of tiles is held in VDP_CT

The actual data is stored in the VDP_Buffer

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

We need to mask the count to a whole number of tiles, we do this with AND #%11111100

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to a tile count - effectively dividing Xpos,Ypos, Width and Height by 4

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return

The Tilemap is easy to use, but hardly allows us smooth movement...

Next time we'll upgrade the code to use Hardware sprites... and get things really moving!

Lesson S27 - Hardware Sprite Clipping on the NES
Using the Tilemap isn't so useful for moving objects, as we can't shift the co-ordinates at the pixel level,

This time, lets do the same as last time, but we'll make our 48x48 pixel sprite out of 6x6 hardware sprites for smooth moves!

NES_Bitmap_Clipping_Hsprite.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


Our logical units are in 2x2 pixel blocks, but our tiles are 8x8 pixels, therefore we can only draw movements of our graphics in 4x4 logical unit 'jumps'

Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the first tile pattern

If there is nothing onscreen, 'DoCrop' will return the Carry set.
We need to build our object out of 8x8 pixel hardware sprites, we'll need to keep a pointer to the next available hardware sprite, we use 'HspriteNum' for this.

We need to set the 4 bytes that define each sprite, we write these to the buffer 'SpriteBuffer' - this is copied to sprite VRAM during the V-Blank NMI.

Each sprite needs to be spaced 8 pixels apart, so we add 8 to the Xpos after each sprite, and 8 to the Ypos after each line
The NMI interrupt handler transfers the buffer to sprite ram with port $4014.

We just write the top byte of the buffer address to this port
our Chibiko usually uses 36 sprites, but if it goes partially offscreen it will use less,

We need to zero the unused sprites to clear these.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop...

we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

If the top line is partially off the screen we need to convert the ypos so the sprite starts partially offscreen, we do this with EOR #%00000011
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We need to convert it to a number of sprites (4 logical units) with AND #%11111100

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.

We add 4 to the amount to remove, as we're overstating the size of the screen by 4 logical units to allow for the 'partially offscreen' sprites drawn at the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and adjust the starting draw with an EOR #%00000011 to correct the starting position to adjust for the removed sprites
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units to pixels and spritesto a tile count - effectively dividing  Width and Height by 4 and multiplying Xpos and Ypos by 2

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return


Remeber! The NES only has 64 hardware sprites, so this will only work for a maximum single object of 8x8 tiles (64x64 pixels) - so drawing 48x48 pixel sprites like this isn't so realistic for a complete game
That's why we used tiles last time, as we can draw as many tiles as we want!


Lesson S28 -  Tile Bitmap Clipping on the SNES
We drew our 'Chibiko' mascot on the SNES using the tilemap before, this time we'll improve the code, allowing the image to be clipped.

Lets have a go!

SNS_Bitmap_Clipping.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


Our logical units are in 2x2 pixel blocks, but our tiles are 8x8 pixels, therefore we can only draw movements of our graphics in 4x4 logical unit 'jumps'

Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the first tile pattern

If there is nothing onscreen, 'DoCrop' will return the Carry set.
We don't actually write to the tilemap, we write to a cache of changes that will be written during the next vblank

GetVDPScreenPos calculates the address in the cache to change in HL

We then write the new tile number... we repeat this for each line of the tilemap

After a line of the tilemap, we update the source tile number to compensate for any clipping with "NoSpriteClip"
When we want to change a tile, we calculate the address of the tile we want to change in VRAM, we write the HL pair of the destination address into the VDPBuffer, a third byte needs to be written to tell the NMI what tile to set.

We can only set a total of 32 tiles per NMI in this way, so if there are already 32*3 bytes in the buffer we wait for the VBlank
The NMI interrupt handler transfers all the tiles to change during VBLANK.

We use the DMA to do this... but it has a lot of settings we need to configure to transfer the data!

Here's the correct settings for the tilemap.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

We need to mask the count to a whole number of tiles, we do this with AND #%11111100

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to a tile count - effectively dividing Xpos,Ypos, Width and Height by 4

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return

The Tilemap is easy to use, but hardly allows us smooth movement...

Next time we'll upgrade the code to use Hardware sprites... and get things really moving!

Lesson S29 - Hardware Sprite Clipping on the SNES
Using the Tilemap isn't so useful for moving objects, as we can't shift the co-ordinates at the pixel level,

This time, lets do the same as last time, but we'll make our 48x48 pixel sprite out of 6x6 hardware sprites for smooth moves!

SNS_Bitmap_Clipping_Hsprite.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


We can now move our sprite in pixels, but our sprites are still 8x8 pixel ' blocks', we'll need to combine lots of hardware sprites to make our character (6*6=36 hsprites)

Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the first tile pattern

If there is nothing onscreen, 'DoCrop' will return the Carry set.
We shift our X and Y position by -8

This is to allow sprites to be partially offscreen at the top and left of the screen.

If our Xpos goes negative, we need to set the top bit (Xpos can be 0-511) - this is stored in z_L
We need to build our object out of 8x8 pixel hardware sprites, we'll need to keep a pointer to the next available hardware sprite, we use 'HspriteNum' for this.

We use "SetHardwareSprite" to set the hardware sprites

Each sprite needs to be spaced 8 pixels apart, so we add 8 to the Xpos after each sprite, and 8 to the Ypos after each line

After each line of the sprite, if the sprite has been cropped on the left or right we skip the patterns with spritehclip
Each of the sprites use 2 words in the first 256 word range... there's also 2 bits in the second 256 word range (4 sprites are combined in one byte)


We use the DMA to transfer the sprite cache during NMI...
but it has a lot of settings we need to configure to transfer the data!

our Chibiko usually uses 36 sprites, but if it goes partially offscreen it will use less,

We need to zero the unused sprites to clear these.

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop...

we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

If the top line is partially off the screen we need to convert the ypos so the sprite starts partially offscreen, we do this with EOR #%00000011
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We need to convert it to a number of sprites (4 logical units) with AND #%11111100

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.

We add 4 to the amount to remove, as we're overstating the size of the screen by 4 logical units to allow for the 'partially offscreen' sprites drawn at the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and adjust the starting draw with an EOR #%00000011 to correct the starting position to adjust for the removed sprites
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units to pixels and spritesto a tile count - effectively dividing  Width and Height by 4 and multiplying Xpos and Ypos by 2

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return




Lesson S30 - Tile Bitmap Clipping on the PC-Engine/Turbografix
We drew our 'Chibiko' mascot on the PC-Engine using the tilemap before, this time we'll improve the code, allowing the image to be clipped.

Lets have a go!

PCE_Bitmap_Clipping.asm

Logical Units and clipping

To allow us to crop our sprites, we'll need to move our sprite around 'logical space' - only a portion of this will be the visible screen.

We'll use this to crop the sprite.


We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit)

The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side.
We need to crop any offscreen part to get to the first visible pixel of the sprite.

After each line We also need to crop the unused pixels to the next visible pixel


Our logical units are in 2x2 pixel blocks, but our tiles are 8x8 pixels, therefore we can only draw movements of our graphics in 4x4 logical unit 'jumps'

Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop"

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the first tile pattern - We use tile pattern 384 (128+256)

If there is nothing onscreen, 'DoCrop' will return the Carry set.
When we want to write to the tilemap, we first use 'GetVDPScreenPos' to select the destination memory address from XY co-ordinate.

We need to select Video reg #2 with ST0, we then write the tile number to $0102/3

After one line, we may need to skip some patterns before starting the next line (if our sprite is off the sides of the screen) - we do this with SpriteHClip.
When we want to change a tile, we calculate the address of the tile we want to change in VRAM. We need to use Video Reg #0 to select the memory address, we then write the address to $0102/3

Our Tilemap starts at memory address $0000, the tilemap is 32*32, each address holds 1 word (One tile), so our formula is

VRAM= Ypos*32 + Xpos

Logical Cropping

Our cropping routine will work out the X,Y pos in bytes, and width and height + any skipped pixels from the source data

Zeropage pair z_bc is the X,Y co-ordinate in logical units
Zeropage pair z_hl is the Width,Height in logical units
Zeropage pair z_iy is the source bitmap address of the sprite data

First we zero z_DE - it's used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line
Ok... lets crop the top of the sprite...
First we remove the ypos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the top.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite, if the amount to crop is not less than the height then the sprite is completely offscreen.

We need to mask the count to a whole number of tiles, we do this with AND #%11111100

Anything else is the number of lines we need to remove from the top, we store this in z_e and set the new 'draw position' to Ypos (z_c) =0
Next we do the same for the bottom,

We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop

We've calculated the top and bottom crop... we now use these to calculate the new height of the sprite.
We then skip over any bytes in the source (z_iy) based on the number of lines we need to remove from the top.
now we do the same for the X axis

First we remove the xpos of the first visible pixel... if the result is greater than zero, then nothing is off the screen at the left.

if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite, if the amount to crop is not less than the width then the sprite is completely offscreen.

Anything else is the number of lines we need to remove from the left, we store this in z_e and set the new 'draw position' to Xpos (z_c) =0
Next we do the same for the right,

We add the width to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop
We've calculated the left and right crop... we now use these to calculate the new width of the sprite.

We then skip over any bytes in the source (z_iy) based on the number of bytes we need to remove from the left.
We've finished cropping our sprite!... but we need to convert our co-ordinates from logical units (pairs of pixels) to a tile count - effectively dividing Xpos,Ypos, Width and Height by 4

We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return.
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return

The Tilemap is easy to use, but hardly allows us smooth movement...

Next time we'll upgrade the code to use Hardware sprites... and get things really moving!




 

View Options
Default Dark
Simple (Hide this menu)
Print Mode (white background)

Top Menu
***Main Menu***
Youtube channel
Forum
AkuSprite Editor
Dec/Bin/Hex/Oct/Ascii Table

Z80 Content
***Z80 Tutorial List***
Learn Z80 Assembly
Hello World
Advanced Series
Multiplatform Series
Platform Specific Series
ChibiAkumas Series
Grime Z80
Z80 Downloads
Z80 Cheatsheet
Sources.7z
DevTools kit
Z80 Platforms
Amstrad CPC
Elan Enterprise
Gameboy & Gameboy Color
Master System & GameGear
MSX & MSX2
Sam Coupe
TI-83
ZX Spectrum
Spectrum NEXT
Camputers Lynx

6502 Content
***6502 Tutorial List***
Learn 6502 Assembly
Advanced Series
Platform Specific Series
Hello World Series
Grime 6502
6502 Downloads
6502 Cheatsheet
Sources.7z
DevTools kit
6502 Platforms
Apple IIe
Atari 800 and 5200
Atari Lynx
BBC Micro
Commodore 64
Commander x16
Super Nintendo (SNES)
Nintendo NES / Famicom
PC Engine (Turbografx-16)
Vic 20

68000 Content
***68000 Tutorial List***
Learn 68000 Assembly
Hello World Series
Platform Specific Series
Grime 68000
68000 Downloads
68000 Cheatsheet
Sources.7z
DevTools kit
68000 Platforms
Amiga 500
Atari ST
Neo Geo
Sega Genesis / Mega Drive
Sinclair QL
X68000 (Sharp x68k)

8086 Content
Learn 8086 Assembly
Platform Specific Series
Hello World Series
8086 Downloads
8086 Cheatsheet
Sources.7z
DevTools kit
8086 Platforms
Wonderswan
MsDos

ARM Content
Learn ARM Assembly
Platform Specific Series
ARM Downloads
ARM Cheatsheet
Sources.7z
DevTools kit
ARM Platforms
Gameboy Advance
Nintendo DS
Risc Os

Risc-V Content
Learn Risc-V Assembly
Risc-V Downloads
Risc-V Cheatsheet
Sources.7z
DevTools kit

PDP-11 Content
Learn PDP-11 Assembly
PDP-11 Downloads
PDP-11 Cheatsheet
Sources.7z
DevTools kit

TMS9900 Content
Learn TMS9900 Assembly
TMS9900 Downloads
TMS9900 Cheatsheet
Sources.7z
DevTools kit
TMS9900 Platforms
Ti 99

6809 Content
Learn 6809 Assembly
6809 Downloads
6809/6309 Cheatsheet
Sources.7z
DevTools kit
6809 Platforms
Dragon 32/Tandy Coco
Fujitsu FM7
TRS-80 Coco 3
Vectrex

My Game projects
Chibi Aliens
Chibi Akumas

Work in Progress
Learn 65816 Assembly
Learn eZ80 Assembly

Misc bits
Ruby programming









Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book

Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!












































Recent New Content
Lesson P34 - Creating a game for the NeoGeo CD!

Sprite Movement on the Dragon 32- Simple 6502 ASM Lesson S1

Amiga - ASM PSET and POINT for Pixel Plotting

Learn 65816 Assembly: 8 and 16 bit modes on the 65816

SNES - ASM PSET and POINT for Pixel Plotting

ARM Assembly Lesson H3

Lesson P65 - Mouse reading on the Sam Coupe

Mouse Reading in MS-DOS

Risc-V Assembly Lesson 3 - Bit ops and more maths!

Mouse reading on the MSX

Hello World on RISC-OS

Atari 800 / 5200 - ASM PSET and POINT for Pixel Plotting


Gaming + more:

Emily The Strange (DS) - Live full playthrough

$150 calculator: Unboxing the Ti-84 Plus CE (eZ80 cpu)




































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book

Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!












































Recent New Content
Lesson P34 - Creating a game for the NeoGeo CD!

Sprite Movement on the Dragon 32- Simple 6502 ASM Lesson S1

Amiga - ASM PSET and POINT for Pixel Plotting

Learn 65816 Assembly: 8 and 16 bit modes on the 65816

SNES - ASM PSET and POINT for Pixel Plotting

ARM Assembly Lesson H3

Lesson P65 - Mouse reading on the Sam Coupe

Mouse Reading in MS-DOS

Risc-V Assembly Lesson 3 - Bit ops and more maths!

Mouse reading on the MSX

Hello World on RISC-OS

Atari 800 / 5200 - ASM PSET and POINT for Pixel Plotting


Gaming + more:

Emily The Strange (DS) - Live full playthrough

$150 calculator: Unboxing the Ti-84 Plus CE (eZ80 cpu)




































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book

Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!












































Recent New Content
Lesson P34 - Creating a game for the NeoGeo CD!

Sprite Movement on the Dragon 32- Simple 6502 ASM Lesson S1

Amiga - ASM PSET and POINT for Pixel Plotting

Learn 65816 Assembly: 8 and 16 bit modes on the 65816

SNES - ASM PSET and POINT for Pixel Plotting

ARM Assembly Lesson H3

Lesson P65 - Mouse reading on the Sam Coupe

Mouse Reading in MS-DOS

Risc-V Assembly Lesson 3 - Bit ops and more maths!

Mouse reading on the MSX

Hello World on RISC-OS

Atari 800 / 5200 - ASM PSET and POINT for Pixel Plotting


Gaming + more:

Emily The Strange (DS) - Live full playthrough

$150 calculator: Unboxing the Ti-84 Plus CE (eZ80 cpu)