Wednesday, August 3, 2016

Now I am done with updating my animation engine!

Here is the almost unreadable code for it:

no_animation_slot:
jsr clear_vram_slot
stz {frame_id}
rts

animation:
lda {animation_update}
bne +
lda {metasprite_request}
cmp {metasprite}
bne +
rts
+;
lda #$0000
ldy {metasprite_request}
beq no_animation_slot
lda $000c,y

sta {vram_size}
clc
adc {total_dma_legnth}
cmp #$0080
beq yes_metasprite_pattern
bcc yes_metasprite_pattern
lda {first_object_to_dma}
bne +
tdc
sta {first_object_to_dma}
+;
no_metasprite_pattern:
rts
yes_metasprite_pattern:


jsr clear_vram_slot
ldy {metasprite_request}
lda $000a,y
asl #5
sta {vram_width}


dynamic_animation:

lda {rotation_disable}
bne +
stz {180_degrees_flip}
lda {angle}
cmp #$8000
bcc +
lda #$c000
sta {180_degrees_flip} //this is so rotation of 180 degrees doesn't happen until
+; //the frame gets updated
stz {animation_update}


lda {metasprite_request}
sta {metasprite}
tay


lda $000e,y
clc
adc {animation_index}
inc #2
sta {frame_id}
tax
lda {animation_copies},x
beq +
inc
sta {animation_copies},x
rts
+;
inc
sta {animation_copies},x



lda $0006,y
clc
adc {graphics_address}
sta {temp3}
lda $0008,y
sta {temp2}
lda $0010,y
bpl +
tya
clc
adc {animation_index}
tay
lda $0010,y
tay
+;

-;
lda $0010,y
bne +
lda #$ffff
sta {animation_chr},x
rts
+;
lda $0018,y
sta {temp}
jsr find_vram_slot
sta {animation_chr},x
cmp #$ffff
bne +
tya
clc
adc #$000a
tay
bra -
+;
tax
-;


lda $0010,y
sta {sprite_size},x
lda $0012,y
sta {sprite_x},x
lda $0014,y
sta {sprite_y},x
lda $0016,y
sta {sprite_attributes},x
tya
clc
adc #$000a
tay
lda $0018,y
sta {temp}
lda $0010,y
beq +
jsr find_vram_slot
sta {sprite_name},x
cmp #$ffff
beq -
tax
bra -
+;
lda #$ffff
sta {sprite_name},x

lda {vram_size}
clc
adc {total_dma_legnth}
sta {total_dma_legnth}
rts


find_vram_slot:
phx
lda $0010,y
cmp #$0002
beq large_slot
jmp small_slot
large_slot:
ldx {large_slot_stack_index}
dex
dex
bpl +
lda #$ffff
plx
rts
+;

lda {large_slot_stack},x
stx {large_slot_stack_index}

tax
phy
ldy {dma_updates}


lda {temp}
clc
adc {temp3}
sta {dma_address},y
adc {vram_width}
sta {dma_address}+2,y
adc {vram_width}
sta {dma_address}+4,y
adc {vram_width}
sta {dma_address}+6,y
sep #$20
lda {temp2}
sta {dma_bank},y
sta {dma_bank}+2,y
sta {dma_bank}+4,y
sta {dma_bank}+6,y
lda #$80
sta {dma_legnth},y
sta {dma_legnth}+2,y
sta {dma_legnth}+4,y
sta {dma_legnth}+6,y
rep #$20
txa
and #$01ff
asl #4
sta {dma_destination},y
adc #$0100
sta {dma_destination}+2,y
adc #$0100
sta {dma_destination}+4,y
adc #$0100
sta {dma_destination}+6,y


tya
adc #$0008
tay
lda #$0000
sta {dma_legnth},y
sty {dma_updates}

ply
txa
plx
rts


small_slot:

ldx {small_slot_stack_index}
dex
dex
bpl +
lda #$ffff
plx
rts
+;
lda {small_slot_stack},x
stx {small_slot_stack_index}

tax
phy
ldy {dma_updates}



lda {temp}
clc
adc {temp3}
sta {dma_address},y
adc {vram_width}
sta {dma_address}+2,y

sep #$20
lda {temp2}
sta {dma_bank},y
sta {dma_bank}+2,y
lda #$40
sta {dma_legnth},y
sta {dma_legnth}+2,y
rep #$20
txa
and #$01ff
asl #4
sta {dma_destination},y
adc #$0100
sta {dma_destination}+2,y


iny #4

lda #$0000
sta {dma_legnth},y
sty {dma_updates}

ply
txa
plx
rts

no_slot_to_clear:
rts

clear_vram_slot:

ldy {metasprite}
beq no_slot_to_clear

ldx {frame_id}
beq no_slot_to_clear
lda {animation_copies},x
beq +
dec
sta {animation_copies},x
bne no_slot_to_clear
+;


lda {animation_chr},x
tax

-;

cpx #$ffff
beq no_slot_to_clear
lda {sprite_size},x
beq no_slot_to_clear
tay
phx
txa
cpy #$0002
beq +
ldx {small_slot_stack_index}
sta {small_slot_stack},x
inx
inx
stx {small_slot_stack_index}

bra ++
+;
ldx {large_slot_stack_index}
sta {large_slot_stack},x
inx
inx
stx {large_slot_stack_index}

+;

plx
lda #$0000
sta {sprite_size},x
lda {sprite_name},x
tax
jmp -
 Basically what it does, is compares the previous metasprite with the current one, or checks if the animation update flag is set, to see if there is a change in animation frame.  When there is, it looks at the size of the metasprite to keep track of DMA usage.  If it spills over 4kB in one frame, it doesn't update it until the next frame.  If there is enough DMA time, it clears the previous animation frame from the tables (see below).

Then it looks at the metasprite's frame number, uses that as an index to a super long list holding both the CHR bits for the first sprite, and the amount of copies that frame has.  If there were no copies of that frame already being used, it creates a linked list table for it.  First it finds an unused CHR name for the first sprite (0-127 are for 16x16 sprites, 128-511 are for 32x32 sprites), then it uses that number as the entry point for the vram linked sprite table, where every CHR number has a cooresponding X-displacement, Y-displacement, attributes word, and the CHR number for the next sprite in the frame/metasprite.

Clearing the animation frame is basically getting all the sprites off the linked list, and putting them back on the list of empty vram slots.  Displaying an animation frame, involves going through the linked list, adding the X and Y coordinates, and putting it on the OAM.

If you're reading this, I've probably lost you, and that is the problem with programming.  I share my codes with people so they don't have to reinvent the wheel, but when I do, it confuses the shit out of them.