mirror of
https://github.com/deater/dos33fsprogs.git
synced 2024-12-30 22:32:48 +00:00
365 lines
6.9 KiB
ArmAsm
365 lines
6.9 KiB
ArmAsm
; Lo-res fire animation, size-optimized
|
|
|
|
; by deater (Vince Weaver) <vince@deater.net>
|
|
|
|
; based on code described here http://fabiensanglard.net/doom_fire_psx/
|
|
|
|
FIRE_YSIZE=20
|
|
|
|
;=======================
|
|
; fire_init
|
|
;=======================
|
|
; call at beginning to clear out framebuffer
|
|
|
|
fire_init:
|
|
lda #<fire_framebuffer
|
|
sta FIRE_FB_L
|
|
|
|
lda #>fire_framebuffer
|
|
sta FIRE_FB_H
|
|
|
|
ldx #FIRE_YSIZE
|
|
clear_fire_loop:
|
|
|
|
lda #0
|
|
ldy #39
|
|
clear_fire_line_loop:
|
|
sta (FIRE_FB_L),Y
|
|
dey
|
|
bpl clear_fire_line_loop
|
|
done_fire_line_loop:
|
|
|
|
clc
|
|
lda FIRE_FB_L
|
|
adc #40
|
|
sta FIRE_FB_L
|
|
bcc skip_inc_hi
|
|
inc FIRE_FB_H
|
|
skip_inc_hi:
|
|
|
|
dex
|
|
bne clear_fire_loop
|
|
|
|
lda #7
|
|
;fall through
|
|
;jsr fire_setline
|
|
|
|
;rts
|
|
|
|
|
|
|
|
;======================================
|
|
; set bottom line to color in A
|
|
;======================================
|
|
; Set to 7 to init, Set to 0 to have fire go out
|
|
fire_setline:
|
|
|
|
ldx #<(fire_framebuffer+(FIRE_YSIZE-1)*40)
|
|
stx FIRE_FB_L
|
|
|
|
ldx #>(fire_framebuffer+(FIRE_YSIZE-1)*40)
|
|
stx FIRE_FB_H
|
|
|
|
ldy #39
|
|
set_fire_line:
|
|
sta (FIRE_FB_L),Y
|
|
dey
|
|
bpl set_fire_line
|
|
done_set_fire_line:
|
|
|
|
rts
|
|
|
|
|
|
;===============================
|
|
;===============================
|
|
; Draw fire frame
|
|
;===============================
|
|
;===============================
|
|
|
|
draw_fire_frame:
|
|
|
|
;===============================
|
|
; Update fire frame
|
|
;===============================
|
|
; Unroll x 2
|
|
|
|
; set up working line (to store to)
|
|
|
|
lda #<fire_framebuffer ; 2
|
|
sta fire_smc5_fb+1 ; 4
|
|
lda #>fire_framebuffer ; 2
|
|
sta fire_smc5_fb+2 ; 4
|
|
|
|
; set up input line, one below, (to load from)
|
|
|
|
lda #<(fire_framebuffer+40) ; 2
|
|
sta fire_smc5_fb2+1 ; 4
|
|
lda #>(fire_framebuffer+40) ; 2
|
|
sta fire_smc5_fb2+2 ; 4
|
|
|
|
|
|
; loop X (ypos) from 0 - FIRE_YSIZE-1
|
|
|
|
ldx #0 ; 2
|
|
fire_fb_update:
|
|
|
|
; FIXME: optimize
|
|
; original = ??? (complex)
|
|
; TODO: unroll once and combine with the lores copy on even lines?
|
|
|
|
|
|
; Loop Y (xpos) from 39 to 0
|
|
ldy #39 ; 2
|
|
fire_fb_update_loop:
|
|
|
|
; Get random 16-bit number
|
|
|
|
jsr random16 ; 40
|
|
|
|
; A randomly has either SEEDL or SEEDH here, I guess that's enough?
|
|
|
|
; get random number Q 0..3
|
|
; Q used to see if whether we grab same lower value or if decrement
|
|
|
|
and #$3 ; 2
|
|
sta FIRE_Q ; 3
|
|
|
|
; 0..12 = A volume, 13-25 = B volume, 26-39 = C volume
|
|
|
|
lda A_VOLUME ; 3
|
|
cpy #13 ; 2
|
|
bcc fire_vol ; blt ; 2/3
|
|
lda B_VOLUME ; 3
|
|
cpy #26 ; 2
|
|
bcc fire_vol ; blt ; 2/3
|
|
lda C_VOLUME ; 3
|
|
fire_vol:
|
|
and #$f ; 2
|
|
|
|
; adjust fire height with volume
|
|
|
|
cmp #$8 ; 2
|
|
bcs fire_medium ; bge ; 2/3
|
|
fire_low:
|
|
; Q=1 3/4 of time
|
|
lda FIRE_Q ; 3
|
|
bne fire_one ; 0-3, is not 0 3/4 of time ; 2/3
|
|
beq fire_set ; 3
|
|
fire_medium:
|
|
cmp #$d ; 2
|
|
lda FIRE_Q ; 3
|
|
bcs fire_high ; bge ; 2/3
|
|
|
|
; Q=1 1/2 of time
|
|
and #$1 ; 2
|
|
bcc fire_set ; branch always ; 3
|
|
fire_high:
|
|
; Q=1 1/4 of time
|
|
;;lda FIRE_Q ; is 0 1/4 of time ; 3
|
|
bne fire_zero ; 2/3
|
|
fire_one:
|
|
lda #1 ; 2
|
|
bne fire_set ; 3
|
|
fire_zero:
|
|
lda #0 ; 2
|
|
fire_set:
|
|
sta FIRE_Q ; 3
|
|
|
|
|
|
|
|
;=================
|
|
; check if flame from left/right
|
|
|
|
; store Y as we over-write it
|
|
sty FIRE_Y ; 3
|
|
|
|
; bounds check
|
|
; on edges, don't wrap
|
|
|
|
tya ; 2
|
|
beq fire_r_same ; 2/3
|
|
cpy #39 ; 2
|
|
beq fire_r_same ; 2/3
|
|
|
|
; RAND_R
|
|
; 50% chance fire comes from below
|
|
; 25% chance comes from right
|
|
; 25% change comes from left
|
|
|
|
lda SEEDH ; 3
|
|
lsr ; 2
|
|
and #$1 ; 2
|
|
bne fire_r_same ; 2/3
|
|
bcc r_up ; 2/3
|
|
r_down:
|
|
dey ; 2
|
|
.byte $a9 ; 2
|
|
r_up:
|
|
iny ; 2
|
|
fire_r_same:
|
|
|
|
; get next line color
|
|
fire_smc5_fb2:
|
|
lda $1234,Y ; 4+
|
|
|
|
; restore saved Y
|
|
ldy FIRE_Y ; 3
|
|
|
|
; have value, subtract Q
|
|
sec ; 2
|
|
sbc FIRE_Q ; 3
|
|
|
|
; saturate to 0
|
|
bpl fb_positive ; 2/3
|
|
lda #0 ; 2
|
|
fb_positive:
|
|
|
|
; store out
|
|
fire_smc5_fb:
|
|
sta $1234,Y ; store out ; 5
|
|
|
|
dey ; 2
|
|
bpl fire_fb_update_loop ; 2/3
|
|
|
|
done_fire_fb_update_loop:
|
|
|
|
; if just finished odd line, we are already set up
|
|
; to do the framebuffer copy for the prev two lines?
|
|
|
|
|
|
|
|
; complicated adjustment
|
|
clc ; 2
|
|
lda fire_smc5_fb+1 ; 4
|
|
adc #40 ; 2
|
|
sta fire_smc5_fb+1 ; 4
|
|
bcc skip_fb_inc1 ; 2/3
|
|
inc fire_smc5_fb+2 ; 4
|
|
clc ; 2
|
|
skip_fb_inc1:
|
|
|
|
lda fire_smc5_fb2+1 ; 4
|
|
adc #40 ; 2
|
|
sta fire_smc5_fb2+1 ; 4
|
|
bcc skip_fb2_inc1 ; 2/3
|
|
inc fire_smc5_fb2+2 ; 4
|
|
skip_fb2_inc1:
|
|
|
|
inx ; 2
|
|
cpx #(FIRE_YSIZE-1) ; 2
|
|
;beq fire_update_done ; 2/3
|
|
bne fire_fb_update ; 3
|
|
|
|
fire_update_done:
|
|
|
|
|
|
|
|
;===================================
|
|
; copy framebuffer to low-res screen
|
|
;===================================
|
|
|
|
lda #<fire_framebuffer ; 2
|
|
sta fire_smc_fb+1 ; 5
|
|
lda #<(fire_framebuffer+40) ; 2
|
|
sta fire_smc_fb2+1 ; 5
|
|
|
|
lda #>fire_framebuffer ; 2
|
|
sta fire_smc_fb+2 ; 5
|
|
;this lda could be omitted if values match
|
|
lda #>(fire_framebuffer+40) ; 2
|
|
sta fire_smc_fb2+2 ; 5
|
|
|
|
lda #16 ; 2
|
|
sta FIRE_FB_LINE ; 3
|
|
|
|
ldx #(FIRE_YSIZE/2) ; 2
|
|
|
|
fire_fb_copy:
|
|
|
|
ldy FIRE_FB_LINE ; 3
|
|
iny ; 2
|
|
iny ; 2
|
|
sty FIRE_FB_LINE ; 3
|
|
|
|
|
|
; Set up output, self-modifying code
|
|
lda gr_offsets,Y ; 4+
|
|
sta fire_smc_outl+1 ; 4
|
|
lda gr_offsets+1,Y ; 4+
|
|
clc ; 2
|
|
adc DRAW_PAGE ; 3
|
|
sta fire_smc_outl+2 ; 4
|
|
|
|
; FIXME: below, can we do this better?
|
|
; 50: original code
|
|
; 39: move to big lookup table
|
|
; 33: move save/restore X outside inner loop
|
|
; 30: self-modifying code
|
|
|
|
ldy #39 ; 2
|
|
stx FIRE_X ; 3
|
|
fire_fb_copy_loop:
|
|
; get top byte
|
|
; note, seems backwards, apple II LORES bottom byte is on top
|
|
fire_smc_fb2:
|
|
lda $1234,Y ; 4+
|
|
asl ; 2
|
|
asl ; 2
|
|
asl ; 2
|
|
; get bottom byte
|
|
fire_smc_fb:
|
|
ora $1234,Y ; 4+
|
|
tax ; 2
|
|
lda fire_colors,X ; 4+
|
|
fire_smc_outl:
|
|
sta $1234,Y ; store out ; 5
|
|
|
|
dey ; 2
|
|
bpl fire_fb_copy_loop ; 2/3
|
|
done_fire_fb_copy_loop:
|
|
ldx FIRE_X ; 3
|
|
|
|
|
|
; complicated adjustment
|
|
clc ; 2
|
|
lda fire_smc_fb+1 ; 4
|
|
adc #80 ; 2
|
|
sta fire_smc_fb+1 ; 5
|
|
bcc skip_fb_inc2 ; 2/3
|
|
inc fire_smc_fb+2 ; 5
|
|
clc ; 2
|
|
skip_fb_inc2:
|
|
|
|
lda fire_smc_fb2+1 ; 4
|
|
adc #80 ; 2
|
|
sta fire_smc_fb2+1 ; 5
|
|
bcc skip_fb2_inc2 ; 2/3
|
|
inc fire_smc_fb2+2 ; 5
|
|
skip_fb2_inc2:
|
|
|
|
dex ; 2
|
|
bne fire_fb_copy ; 2/3
|
|
|
|
|
|
rts ; 6
|
|
|
|
;fire_colors_low: .byte $00,$00,$03,$02,$06,$07,$0E,$0F
|
|
;fire_colors_high: .byte $00,$00,$30,$20,$60,$70,$E0,$F0
|
|
|
|
fire_colors:
|
|
; 0 1 2 3 4 5 6 7
|
|
; 0 0 3 2 6 7 e f
|
|
.byte $00,$00,$03,$02,$06,$07,$0e,$0f ; 0
|
|
.byte $00,$00,$03,$02,$06,$07,$0e,$0f ; 0
|
|
.byte $30,$30,$33,$32,$36,$37,$3e,$3f ; 3
|
|
.byte $20,$20,$23,$22,$26,$27,$2e,$2f ; 2
|
|
.byte $60,$60,$63,$62,$66,$67,$6e,$6f ; 6
|
|
.byte $70,$70,$73,$72,$76,$77,$7e,$7f ; 7
|
|
.byte $e0,$e0,$e3,$e2,$e6,$e7,$ee,$ef ; e
|
|
.byte $f0,$f0,$f3,$f2,$f6,$f7,$fe,$ff ; f
|
|
|
|
; FIXME: just reserve space in our memory map
|
|
fire_framebuffer:
|
|
.res 40*FIRE_YSIZE, $00
|
|
|