"Soft" sprites

Basic and Machine Language

Moderator: Moderators

derekwinters
Vic 20 Newbie
Posts: 10
Joined: Fri Apr 09, 2021 4:35 am

Re: "Soft" sprites

Post by derekwinters »

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
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: "Soft" sprites

Post by Mike »

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.
derekwinters
Vic 20 Newbie
Posts: 10
Joined: Fri Apr 09, 2021 4:35 am

Re: "Soft" sprites

Post by derekwinters »

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
User avatar
Noizer
Vic 20 Devotee
Posts: 297
Joined: Tue May 15, 2018 12:00 pm
Location: Europa

Re: "Soft" sprites

Post by Noizer »

derekwinters 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!.
...
Code: let's see, then let's look over it
BR
Valid rule today as earlier: 1 Byte = 8 Bits
-._/classes instead of masses\_.-
User avatar
AndyH
Vic 20 Afficionado
Posts: 364
Joined: Thu Jun 17, 2004 5:51 am
Website: https://www.hewco.uk
Location: UK
Occupation: Developer

Re: "Soft" sprites

Post by AndyH »

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.
asteroids.gif
--
AndyH
HEWCO | Vic 20 blog
Vic20-Ian
Vic 20 Scientist
Posts: 1214
Joined: Sun Aug 24, 2008 1:58 pm

Re: "Soft" sprites

Post by Vic20-Ian »

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
User avatar
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

Post by chysn »

Vic20-Ian wrote: Wed May 12, 2021 1:23 am Impressive stuff...very busy.
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.
User avatar
AndyH
Vic 20 Afficionado
Posts: 364
Joined: Thu Jun 17, 2004 5:51 am
Website: https://www.hewco.uk
Location: UK
Occupation: Developer

Re: "Soft" sprites

Post by AndyH »

That sounds ace - something like Arcadia perhaps? Kind of arcade vertical orientation :)
--
AndyH
HEWCO | Vic 20 blog
User avatar
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

Post by chysn »

AndyH wrote: Thu May 13, 2021 6:29 am That sounds ace - something like Arcadia perhaps? Kind of arcade vertical orientation :)
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

User avatar
AndyH
Vic 20 Afficionado
Posts: 364
Joined: Thu Jun 17, 2004 5:51 am
Website: https://www.hewco.uk
Location: UK
Occupation: Developer

Re: "Soft" sprites

Post by AndyH »

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.
--
AndyH
HEWCO | Vic 20 blog
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: "Soft" sprites

Post by Mike »

chysn wrote:I'm playing around with a 16x11 character (128x176 pixel) bitmap instead of 20x12 because 16 makes the math ridiculously easy, [...]
Your example code arranges the characters in rows, and that makes the address function of the bitmap much more complicated than it need be.

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
User avatar
AndyH
Vic 20 Afficionado
Posts: 364
Joined: Thu Jun 17, 2004 5:51 am
Website: https://www.hewco.uk
Location: UK
Occupation: Developer

Re: "Soft" sprites

Post by AndyH »

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.
--
AndyH
HEWCO | Vic 20 blog
User avatar
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

Post by chysn »

Mike wrote: Thu May 13, 2021 8:30 am Your example code arranges the characters in rows, and that makes the address function of the bitmap much more complicated than it need be.
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.
AndyH wrote: Thu May 13, 2021 8:17 am 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.
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 :D
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'd like to take a look at it.
User avatar
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

Post by chysn »

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!
User avatar
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

Post by chysn »

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.

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
Post Reply