"Soft" sprites
Moderator: Moderators
-
- Vic 20 Newbie
- Posts: 10
- Joined: Fri Apr 09, 2021 4:35 am
Re: "Soft" sprites
Hi,
Thanks appreciated.
So (and hopefully these aren't silly questions, but I just want to check) : -
1) If I have screen and character generator both start at $1000, then am I right that I would lose a handful of characters from the character set as that's the screen area (64 chars) so my first bitmap char in the screen memory would be 64 ($40)?
2) If I use double height (8x16) chars then I would just need something like 22*11 chars of mem
3) layout the chars in the "matrix" as it was referred to earlier so that chars use the character memory data to allow ($xx),y indexing?
D
Thanks appreciated.
So (and hopefully these aren't silly questions, but I just want to check) : -
1) If I have screen and character generator both start at $1000, then am I right that I would lose a handful of characters from the character set as that's the screen area (64 chars) so my first bitmap char in the screen memory would be 64 ($40)?
2) If I use double height (8x16) chars then I would just need something like 22*11 chars of mem
3) layout the chars in the "matrix" as it was referred to earlier so that chars use the character memory data to allow ($xx),y indexing?
D
- Mike
- Herr VC
- Posts: 4856
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: "Soft" sprites
1) Close. It's more like you only "lose" 16 character definitions at the start of the character set. See my calculation below.
2) 20x12 is a better choice. Again, see below.
3) Yes.
If you want the bitmap to coexist peacefully with BASIC and KERNAL, the best choice is to put text screen and character definition at $1000. Then, the math goes as follows: you need 17 bytes to show a 8x16 tile: 1 byte in the text screen and 16 bytes of character definition. 4096/17 ~= 240.9 - we cannot use partial characters, but 240 characters can nicely be arranged into a matrix of 20x12 double height characters. The text screen occupies 240 bytes, and the first usable screen code is 15. 16 also works for a 'round' start address of the bitmap at $1100. That means, the text screen occupies $1000..$10EF, and the bitmap resides in $1100..$1FFF.
This is exactly the bitmap mode used by MINIGRAFIK. You find more details in appendix C of the MINIPAINT manual.
2) 20x12 is a better choice. Again, see below.
3) Yes.
If you want the bitmap to coexist peacefully with BASIC and KERNAL, the best choice is to put text screen and character definition at $1000. Then, the math goes as follows: you need 17 bytes to show a 8x16 tile: 1 byte in the text screen and 16 bytes of character definition. 4096/17 ~= 240.9 - we cannot use partial characters, but 240 characters can nicely be arranged into a matrix of 20x12 double height characters. The text screen occupies 240 bytes, and the first usable screen code is 15. 16 also works for a 'round' start address of the bitmap at $1100. That means, the text screen occupies $1000..$10EF, and the bitmap resides in $1100..$1FFF.
This is exactly the bitmap mode used by MINIGRAFIK. You find more details in appendix C of the MINIPAINT manual.
-
- Vic 20 Newbie
- Posts: 10
- Joined: Fri Apr 09, 2021 4:35 am
Re: "Soft" sprites
Hi,
Thanks for further replies. I have now managed to get the bitmap mode working as per everyones input.
So now the next job is to get it running in reasonable time as I run out of raster currently with 8 soft sprites on (although i am XOR ing so have to call sprite handler twice), and the ($xx),y seems slow, but that will be my code currently not good enough / inadequate speedwise, not processors fault!.
Thanks again though - closer than I was.
D
Thanks for further replies. I have now managed to get the bitmap mode working as per everyones input.
So now the next job is to get it running in reasonable time as I run out of raster currently with 8 soft sprites on (although i am XOR ing so have to call sprite handler twice), and the ($xx),y seems slow, but that will be my code currently not good enough / inadequate speedwise, not processors fault!.
Thanks again though - closer than I was.
D
Re: "Soft" sprites
Code: let's see, then let's look over itderekwinters wrote: ↑Mon May 10, 2021 4:02 am ...
So now the next job is to get it running in reasonable time as I run out of raster currently with 8 soft sprites on (although i am XOR ing so have to call sprite handler twice), and the ($xx),y seems slow, but that will be my code currently not good enough / inadequate speedwise, not processors fault!.
...
BR
Valid rule today as earlier: 1 Byte = 8 Bits
-._/classes instead of masses\_.-
-._/classes instead of masses\_.-
- AndyH
- Vic 20 Afficionado
- Posts: 370
- Joined: Thu Jun 17, 2004 5:51 am
- Website: https://www.hewco.uk
- Location: UK
- Occupation: Developer
Re: "Soft" sprites
Drawing XOR can have advantages as you don't need to erase / redraw each frame unless it changes (eg: moves or animates) so simply leaving it in place on the bitmap for a frame or two can help with bottlenecks.
Another trick I sometimes use is to have fixed sized sprites, then I can create 'unrolled' sprite drawing code (ie: no loops, but at expense of some memory) to shave off a few cycles.
Also some common stuff like look up tables for the 20 column start addresses and using pre-shifted sprite data as mentioned to reduce the amount of work your routines need to do.
I created a whole suite based on the 160x192 "double hieght" character bitmap described here in Turbo Rascal, with huge thanks to Denial members (several I see on this post) to explain the trick with the VIC memory. With it you can easily set the bitmap mode, draw sprites, text, scroll the screen (cheap and smooth versions) and a number of other handy commands to make it easy to use.
My best game in terms of the number of pixels I throw around (not completed it yet) is Onions (click to view GIF animation) and that's basically using the tips above. It's not 50/60fps but I don't think you can tell. The GIF doesn't really do it justice, smoother on the real device.
Another trick I sometimes use is to have fixed sized sprites, then I can create 'unrolled' sprite drawing code (ie: no loops, but at expense of some memory) to shave off a few cycles.
Also some common stuff like look up tables for the 20 column start addresses and using pre-shifted sprite data as mentioned to reduce the amount of work your routines need to do.
I created a whole suite based on the 160x192 "double hieght" character bitmap described here in Turbo Rascal, with huge thanks to Denial members (several I see on this post) to explain the trick with the VIC memory. With it you can easily set the bitmap mode, draw sprites, text, scroll the screen (cheap and smooth versions) and a number of other handy commands to make it easy to use.
My best game in terms of the number of pixels I throw around (not completed it yet) is Onions (click to view GIF animation) and that's basically using the tips above. It's not 50/60fps but I don't think you can tell. The GIF doesn't really do it justice, smoother on the real device.
Re: "Soft" sprites
Impressive stuff...very busy.
Vic20-Ian
The best things in life are Vic-20
Upgrade all new gadgets and mobiles to 3583 Bytes Free today! Ready
The best things in life are Vic-20
Upgrade all new gadgets and mobiles to 3583 Bytes Free today! Ready
- chysn
- Vic 20 Scientist
- Posts: 1205
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: "Soft" sprites
Yeah, this is a lot of fun, I love the information in this thread.
I'm playing around with a 16x11 character (128x176 pixel) bitmap instead of 20x12 because 16 makes the math ridiculously easy, and I might make a game out of it once the right idea strikes me.
- AndyH
- Vic 20 Afficionado
- Posts: 370
- Joined: Thu Jun 17, 2004 5:51 am
- Website: https://www.hewco.uk
- Location: UK
- Occupation: Developer
Re: "Soft" sprites
That sounds ace - something like Arcadia perhaps? Kind of arcade vertical orientation
- chysn
- Vic 20 Scientist
- Posts: 1205
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: "Soft" sprites
Maybe! It's kind of a whole new world for me, this bitmapping. I'm working on getting some routines written, and I'll see where they take me. This initializes the 16-wide bitmap, and has plot and character write routines. I'm sort of working my way up to sprites now. The problem with sprites is that I can think of so many ways to do them as data structures. I always find that game ideas follow from functionality, so the underlying capabilities usually come first. It seems ass-backward to me, but that's just how I work.
Code: Select all
; 128x176 bitmap mode
; Assembled with XA
; Configuration
VICCR = $9000 ; VIC Chip register offset
SCREEN = $1000 ; Screen memory offset
BITMAP = $1100 ; Bitmap memory offset
COLOR = $9400 ; Color memory offset
CHAR_PAGE = $80 ; Character memory offet
; ROM resources
X_MAP = $8268 ; Table $80,$40,$20,$10,$08,$04,$02,$01 (\)
; Zero page pointers
CURSOR = $f9 ; Cursor pointer (bitmap address)
SPRITE = $fb ; Start of current sprite data
UTIL = $35 ; Utility pointer
* = $a000
; Initialize bitmap area
; A is the default foreground color
Init: ldy #$cc ; Set screen and character map to $1000
sty VICCR+5 ; ,,
ldy #16 ; Set number of columns to 16
sty VICCR+2 ; ,,
ldy #23 ; Set number of lines to 22, and set 16x8
sty VICCR+3 ; character size
ldy VICCR+0 ; Center the 16-character screen for NTSC
iny ; or PAL
iny ; ,,
iny ; ,,
iny ; ,,
iny ; ,,
sty VICCR+0 ; ,,
ldy #0 ; Initialize screen
-loop: tax ; * A is the foreground color for Init call
sta COLOR,y ; * Set foreground color
tya ; * Set character, starting at PETSCII #16
clc ; ,,
adc #$10 ; ,,
sta SCREEN,y ; ,,
txa ; * Restore foreground color for next loop
iny ; ,,
bne loop ; ,,
rts
; Clear the bitmap area
Clear: lda #<BITMAP ; Set cursor to start of bitmap
sta CURSOR ; ,,
lda #>BITMAP ; ,,
sta CURSOR+1 ; ,,
ldx #0
-loop: lda #0 ; Advance one byte at a time, setting each to
sta (CURSOR,x) ; zero
inc CURSOR ; ,,
bne loop ; ,,
inc CURSOR+1 ; ,,
lda CURSOR+1 ; ,,
cmp #>BITMAP+$0b00 ; ,,
bne loop ; ,,
rts
; Set Cursor Position
; Based on X and Y positions
; X range 0-127
; Y range 0-175
SetCursor: txa ; X position to accumulator
pha ; Preserve X for return
and #$f8 ; Bits 0-2 of X are used later
asl ; Double X for number of bytes to add
sta CURSOR ; to the starting character address
lda #>BITMAP ; Offset is bitmap high byte
sta CURSOR+1 ; ,,
tya ; Now handle Y. The high nybble of Y is
lsr ; the number of pages that need to be
lsr ; added to the base bitmap address, since
lsr ; each line of the 16-character grid is
lsr ; 256 bytes
clc ; Add this shifted value to the high byte
adc CURSOR+1 ; of the target address
sta CURSOR+1 ; ,,
tya ; The low nybble of Y is added to the low
and #$0f ; byte of the cursor, determining the
clc ; location within each 16-byte character
adc CURSOR ; ,,
sta CURSOR ; ,,
pla ; Restore X for return
tax ; ,,
rts
; Plot Point
; At X,Y
; X range 0-127
; Y range 0-175
Plot: jsr SetCursor ; Set cursor to the address of the target
txa ; Now I'll use bits 0-2 of X to count off the
pha ; bit to plot within the cursor, from the left
and #$07 ; ,,
tax ; X is the number of bits to count off
lda X_MAP,x ; Here's the value for the pattern
ldx #$00 ; Draw the pattern at the cursor
ora (CURSOR,x) ; ,,
sta (CURSOR,x) ; ,,
pla ; Restore X to its pre-call value
tax ; ,,
rts
; Type Text
; Add PETSCII character in A to cursor position, then advance the cursor
; to the next position. Type will snap to an 8x8 grid. To use the screen
; code in A, call Code instead of Type.
Type: and #$bf ; Convert provided PETSCII value into a
bpl Code ; screen code, for character image lookup.
and #$7f ; To bypass this and use the screen code,
ora #$40 ; call Code directly
Code: sta SPRITE ; Set the character code in the sprite
lda #$00 ; address
sta SPRITE+1 ; ,,
ldy #$03 ; Now multiply it by 8 (code x character size)
-loop: asl SPRITE ; to get the character image offset address
rol SPRITE+1 ; ,,
dey ; ,,
bne loop ; ,,
lda #CHAR_PAGE ; Then, get the full character image address
clc ; into SPRITE by adding the character set
adc SPRITE+1 ; page to the high byte
sta SPRITE+1 ; ,,
ldy #7 ; Copy the character memory to the bitmap
-loop: lda (SPRITE),y ; at the cursor point
sta (CURSOR),y ; ,,
dey ; ,,
bpl loop ; ,,
; Fall through to Advance
; Advance Cursor
; Move the cursor to the next byte address, 16 bits ahead
Advance: lda #$10 ; Advance cursor to the next position in
clc ; preparation for the next call to Text
adc CURSOR ; ,,
sta CURSOR ; ,,
bcc type_r ; ,,
inc CURSOR+1 ; ,,
type_r: rts
; Write String
; Starting at cursor position, write a null terminated string from
; A low byte, Y high byte
WriteStr: sta UTIL ; Set utility pointer to start of text
sty UTIL+1 ; ,,
-loop: ldy #$00 ; Get the next byte
lda (UTIL),y ; ,,
beq write_r ; 0 indicates end of text
jsr Type ; Print at the current cursor position
inc UTIL ; Advance the utility pointer and get
bne loop ; the next character
inc UTIL+1 ; ,,
bne loop ; ,,
write_r: rts
- AndyH
- Vic 20 Afficionado
- Posts: 370
- Joined: Thu Jun 17, 2004 5:51 am
- Website: https://www.hewco.uk
- Location: UK
- Occupation: Developer
Re: "Soft" sprites
Looks like a superb start, your games are fun, unique and really well made so intrigued to see what you come up with.
I use the ROM character for ploting points too - so useful Are you planning to do this on the unexpanded Vic again? I'm guessing you will have just over 1K of unexpanded memory after your bitmap.
If you want anything from VBM let me know. If you can optimise anything I'd be really interested as I did my best to keep the routines as fast as possible with the knowledge I had at the time.
I use the ROM character for ploting points too - so useful Are you planning to do this on the unexpanded Vic again? I'm guessing you will have just over 1K of unexpanded memory after your bitmap.
If you want anything from VBM let me know. If you can optimise anything I'd be really interested as I did my best to keep the routines as fast as possible with the knowledge I had at the time.
- Mike
- Herr VC
- Posts: 4856
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: "Soft" sprites
Your example code arranges the characters in rows, and that makes the address function of the bitmap much more complicated than it need be.chysn wrote:I'm playing around with a 16x11 character (128x176 pixel) bitmap instead of 20x12 because 16 makes the math ridiculously easy, [...]
With a column-wise arrangement, and the column-starts (Y=0) read off a table, there's also no significant advantage of 128 pixels width versus all other screen widths - you just divide the X co-ordinate by 8, fetch low- and high bytes off two tables and place the column-start into zero page. Then, addressing a single pixel is as simple as this:
Code: Select all
TXA
PHA
LSR
LSR
LSR
TAX
LDA col_address_low,X
STA zp
LDA col_address_high,X
STA zp+1
PLA
AND #$07
TAX
LDA (zp),Y
ORA/AND/EOR bit_table,X
STA (zp),Y
RTS
- AndyH
- Vic 20 Afficionado
- Posts: 370
- Joined: Thu Jun 17, 2004 5:51 am
- Website: https://www.hewco.uk
- Location: UK
- Occupation: Developer
Re: "Soft" sprites
ah yes, no need to go with row order, lay out a full column of sequential characters at a time and x position is just a case of which column to start on and y position just an offset in any indirect reference ($xx),y. Everything you do from points to copying bitmap data becomes simple from that point on.
- chysn
- Vic 20 Scientist
- Posts: 1205
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: "Soft" sprites
I'll take the column layout for a spin, thanks! The address function doesn't seem complicated, but I do see the appeal of (ZP),Y. The idea of devoting 40 bytes to a column address table kind of annoys me. But I'll definitely try it out.
Probably not, but the thought crossed my mind. The nice thing about character-based games is that the display memory doubles as a game-state database. Is there something at that coordinate? You know there is! With bitmap, you start with the overhead of all these bits, but then you also need to keep track of state elsewhere, so double whammy.
With expanded memory, my mindset might change, and I'll feel better about this stupid column table
I'd like to take a look at it.If you want anything from VBM let me know. If you can optimise anything I'd be really interested as I did my best to keep the routines as fast as possible with the knowledge I had at the time.
- chysn
- Vic 20 Scientist
- Posts: 1205
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: "Soft" sprites
OK, I'm totally sold on columns, even for the 128x?? layout. It makes my interface different, but it makes positioning of soft sprites much easier.
Whether I acquiesce to a pair of column address tables will depend on the project. ZP ASL and ROL take trillions of cycles, there's just no way around that. But at the moment I'm trying to see how compact I can make a bitmap tool, even at the cost of speed. I understand how to make it faster if I need to.
In a real project, chances are I jettison a single-bit plot routine and focus on sprites. Plot is just a tool for verifying the correct layout and address calculations, and letting me play with sine graphs. But it doesn't otherwise pull its weight. Plus, a single-bit sprite is literally a plot. So once I get some sprite code working, I'll re-post. Back on topic soon!
Whether I acquiesce to a pair of column address tables will depend on the project. ZP ASL and ROL take trillions of cycles, there's just no way around that. But at the moment I'm trying to see how compact I can make a bitmap tool, even at the cost of speed. I understand how to make it faster if I need to.
In a real project, chances are I jettison a single-bit plot routine and focus on sprites. Plot is just a tool for verifying the correct layout and address calculations, and letting me play with sine graphs. But it doesn't otherwise pull its weight. Plus, a single-bit sprite is literally a plot. So once I get some sprite code working, I'll re-post. Back on topic soon!
- chysn
- Vic 20 Scientist
- Posts: 1205
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: "Soft" sprites
I've made five bitmap modes in the last 48 hours, but this last one targets unexpanded (or potentially +3K) VIC. For an unexpanded machine, I'm putting the screen at $1800, with a resolution of 120x128. This is 120 double-height characters occupying $1800-$1878. The characters 0-119 are laid out in 15 columns starting with character #8. Thus, the bitmap data goes from $1880 to $1fff.
The memory from $1000 to $17ff allows 2K of code. I plan to load sprite image data into $1800, and then a short routine will copy the images to the cassette buffer on launch, before the bitmap is initialized. This will allow me to stretch the 2K a little bit further.
I'm using 8x8 sprites. The Stamp routine can be extended to other widths without too much trouble, but my gameplan is to use 8x8. I'm interested in other approaches to positioning sprites in columns. Andy mentioned pre-shifting, which is fine if you have the memory. Otherwise, I don't see much alternative to starting with the snapped-to-0 image and shifting it right into another column.
Mike may notice that (for this mode) I opted out of the column address table in favor of calculation. Why? Because it saves 24 bytes. At the end of a project, I'm always looking for just a few more bytes. 24 doesn't seem like a lot now, but it will. The cost is something like 11 cycles. Right now, I'm okay with the tradeoff. This isn't going to be a fast-paced arcade game; this is going to be a game about piloting a sailboat.
My sprite stamp routine has rudimentary collision detection. You can check a collision flag after the stamp with BIT COLLISION, BMI has_collided. This is detecting whether any of the actual pixels in the bitmap have been placed over a previously-set pixel.
The attached BASIC program for unexpanded VIC demonstrates the stamping, unstamping, and collision detection features.
The memory from $1000 to $17ff allows 2K of code. I plan to load sprite image data into $1800, and then a short routine will copy the images to the cassette buffer on launch, before the bitmap is initialized. This will allow me to stretch the 2K a little bit further.
I'm using 8x8 sprites. The Stamp routine can be extended to other widths without too much trouble, but my gameplan is to use 8x8. I'm interested in other approaches to positioning sprites in columns. Andy mentioned pre-shifting, which is fine if you have the memory. Otherwise, I don't see much alternative to starting with the snapped-to-0 image and shifting it right into another column.
Mike may notice that (for this mode) I opted out of the column address table in favor of calculation. Why? Because it saves 24 bytes. At the end of a project, I'm always looking for just a few more bytes. 24 doesn't seem like a lot now, but it will. The cost is something like 11 cycles. Right now, I'm okay with the tradeoff. This isn't going to be a fast-paced arcade game; this is going to be a game about piloting a sailboat.
My sprite stamp routine has rudimentary collision detection. You can check a collision flag after the stamp with BIT COLLISION, BMI has_collided. This is detecting whether any of the actual pixels in the bitmap have been placed over a previously-set pixel.
The attached BASIC program for unexpanded VIC demonstrates the stamping, unstamping, and collision detection features.
Code: Select all
; VIC Bitmap
; 120x128 bitmap mode
; Configuration
VICCR = $9000 ; VIC Chip register offset
SCREEN = $1800 ; Screen memory offset
BITMAP = $1880 ; Bitmap memory offset
COLOR = $9400 ; Color memory offset
; ROM resources
X_MAP = $8268 ; Table $80,$40,$20,$10,$08,$04,$02,$01 (\)
; Zero page pointers
CURSOR = $f9 ; Cursor pointer (bitmap address)
SPRITE = $fb ; Sprite data pointer (image address)
UTIL = $35 ; Utility
OPERATION = $61 ; Current stamp or unstamp operation
COLLISION = $62 ; Collision detection for stamp
RIGHT = $63 ; Right byte
; This is the tokenization of the following BASIC program, which
; runs the test
; 42 SYS4110
* = $1001
BASIC: .byte $0b,$04,$2a,$00,$9e,$34,$31,$31
.byte $30,$00,$00,$00,$00
Test: ldx #$00 ; Black foreground
jsr Init ; Initialize bitmap
lda #$01 ; Draw an island - Set image
ldx #$15 ; Set X position
ldy #$15 ; Set Y position
sec ; Set carry to stamp
jsr Stamp ; Perform stamp
lda #$00 ; Set starting X,Y for sailboat
sta $05 ; ,,
sta $06 ; ,,
move: jsr boat_on ; Stamp the boat
bit COLLISION ; Has the boat collided with the island?
bmi sink ; If so, sink it and end
lda #$f0 ; Wait a short time
sta $a2 ; ,,
wait: lda $a2 ; ,,
bne wait ; ,,
jsr boat_off ; Unstamp the boat
inc $05 ; Move the boat one pixel southeast
inc $06 ; ,,
jmp move ; And go back
boat_on: sec ; Set carry to stamp
.byte $34 ; (Skip next byte)
boat_off: clc ; Clear carry to unstamp
clear: lda #$00 ; Select sailboat image
ldx $05 ; Set X position
ldy $06 ; Set Y position
jmp Stamp ; Stamp and return
sink: jsr boat_off ; Sink the boat!
end: jmp end
; Initialize Bitmap
; X = Starting foreground color
Init: lda #<SCREEN ; Clear screen area
sta CURSOR ; ,,
lda #>SCREEN ; ,,
sta CURSOR+1 ; ,,
ldy #0
-loop: lda #0 ; Advance one byte at a time, setting each to
sta (CURSOR),y ; zero
iny ; ,,
bne loop ; ,,
inc CURSOR+1 ; ,,
lda CURSOR+1 ; ,,
cmp #>SCREEN+$0800 ; ,,
bne loop ; ,,
lda #$ee ; Set screen and character map to $1800
sta VICCR+5 ; ,,
lda #15 ; Set number of columns to 15
sta VICCR+2 ; ,,
lda #17 ; Set number of lines to 16, and set 16x8
sta VICCR+3 ; character size
lda #$08 ; This is the starting character code (16)
ldy #0 ; Initialize the screen
-loop: pha ; * Set the foreground color
txa ; ,,
sta COLOR,y ; ,,
pla ; ,,
sta SCREEN,y ; * Place the character
clc ; * The next character is 8 bytes away
adc #$08 ; ,,
cmp #$80 ; If we're at the end of the row...
bcc next ;
sbc #$77 ; ...reset to the next row's 1st character
next iny ; ,,
cpy #120 ; (16 x 15) / 2
bne loop
rts
; Set Cursor Address
; Based on X,Y position
; X range 0-119
; Y range 0-127
SetCursor: txa ; Round X down to the nearest character
pha ; Store X for return
lsr ; Get int(X/8)
lsr ; ,,
lsr ; ,,
tax ; ,,
and #$01 ; Low byte alternates between $80 and $00
eor #$01 ; ,,
lsr ; ,,
ror ; ,,
sta CURSOR ; ,,
tya ; Add Y to the cursor low byte. Since the
clc ; range is 0-127, and columns start on
adc CURSOR ; $00 and $80, I don't really care about
sta CURSOR ; handling the carry flag here
inx ; High byte is (X+1)/2 + $18
txa ; ,,
lsr ; ,,
clc ; ,,
adc #>BITMAP ; ,,
sta CURSOR+1 ; ,,
pla ; Return X to original value
tax ; ,,
rts
; Plot Point
; At X,Y
; X range 0-119
; Y range 0-127
Plot: jsr SetCursor ; Set cursor to the address of X,Y character
pha ; Now I'll use bits 0-2 of X to count off the
and #$07 ; bit to plot within the cursor, from the left
tax ; X is the number of bits to count off
lda X_MAP,x ; Here's the value for the pattern
ldx #$00 ; Place that value at the cursor position
ora (CURSOR,x) ; ,,
sta (CURSOR,x) ; ,,
pla ; Restore X to its pre-call value
tax ; ,,
rts
; Stamp
; Stamp or unstamp sprite image at index A at X,Y
; Carry set = stamp (draw the character)
; clear = unstamp (erase the character)
Stamp: ror OPERATION ; Bit 7 indicates the operation
clc ; Clear collision flag
ror COLLISION ; ,,
asl ; Multiply the index times bytes per
asl ; image to get the image table offset
asl ; ,,
sta SPRITE ; Store the offset
lda #<ImgTable ; Add the low byte of the table
clc ; to the previous offset
adc SPRITE ; ,,
sta SPRITE ; ,,
lda #$00 ; Then set the high byte, plus one if carry
adc #>ImgTable ; ,,
sta SPRITE+1 ; ,,
jsr SetCursor ; Set cursor to the address of the target column
lda CURSOR ; Set the right-side pointer to the next
clc ; column to the right. The bitmap memory at
adc #$80 ; this address will take the right-shifted
sta RIGHT ; bits from the cursor address, based on the
lda CURSOR+1 ; specified X value
adc #$00 ; ,,
sta RIGHT+1 ; ,,
txa ; How many shifts need to be done?
and #$07 ; ,,
ldy #7 ; Loop over the sprite, vertically
-loop: pha ; Store number of horizontal shifts
lda (SPRITE),y ; Get next byte from sprite image table
sta UTIL ; Store it temporarilty
lda #$00 ; Start the byte to the right at 0
sta UTIL+1 ; ,,
pla ; X will be the number of horizontal shifts
pha ; Store for next iteration
tax ; ,,
beq horiz_done ; ,,
-loop2: lsr UTIL ; Shift horizontally
ror UTIL+1 ; ,,
dex ; ,,
bne loop2 ; ,,
horiz_done: lda (CURSOR),y ; Check current bitmap contents for collision
bit UTIL ; ,,
beq no_coll_l ; ,,
sec ; Set the collision flag, if collision
ror COLLISION ; ,,
no_coll_l: lda UTIL ; Place the leftmost byte at the cursor
bit OPERATION ; Perform AND ~ or OR, depending on whether
bmi stamp_l ; the operation is stamp or unstamp
eor #$ff ; ,,
and (CURSOR),y ; ,,
.byte $3c ; ,, (Skip next two bytes)
stamp_l: ora (CURSOR),y ; ,,
sta (CURSOR),y ; Update the bitmap
lda (RIGHT),y ; Check current bitmap contents for collision
bit UTIL+1 ; ,,
beq no_coll_r ; ,,
sec ; Set the collision flag, if collision
ror COLLISION ; ,,
no_coll_r: lda UTIL+1 ; Place the next byte at the right pointer
bit OPERATION ; Perform AND ~ or OR, depending on whether
bmi stamp_r ; the operation is stamp or unstamp
eor #$ff ; ,,
and (RIGHT),y ; ,,
.byte $3c ; ,, (Skip next two bytes)
stamp_r: ora (RIGHT),y ; ,,
sta (RIGHT),y ; Update the bitmap
pla ; A is back to number of shifts for next byte
dey
bpl loop
rts
ImgTable: .byte $02,$34,$48,$54,$24,$1c,$02,$00 ; Sailboat - SE
.byte $00,$1d,$1f,$3f,$7e,$7c,$38,$38 ; Island
- Attachments
-
- 5kbitmap.prg.zip
- (820 Bytes) Downloaded 56 times