mirror of https://github.com/nmlgc/ReC98.git
114 lines
3.0 KiB
NASM
114 lines
3.0 KiB
NASM
public CURVEBULLETS_RENDER
|
|
curvebullets_render proc near
|
|
|
|
@@head = word ptr -6
|
|
@@trail_sprite = word ptr -4
|
|
@@bullet_i = word ptr -2
|
|
|
|
@@clip macro @@label_next:req
|
|
local @@positive_y
|
|
add ax, (PLAYFIELD_X - (CURVEBULLET_W / 2))
|
|
cmp dx, (PLAYFIELD_Y - CURVEBULLET_H)
|
|
jl short @@label_next
|
|
cmp dx, PLAYFIELD_BOTTOM
|
|
jge short @@label_next
|
|
or ax, ax
|
|
jl short @@label_next
|
|
cmp ax, PLAYFIELD_RIGHT
|
|
jge short @@label_next
|
|
|
|
; This is usually done in the scroll_subpixel_y_to_vram*() functions. But
|
|
; since curve bullets are only used by bosses whose backgrounds don't
|
|
; scroll, ZUN apparently didn't see the need to call that function here?
|
|
; Y wrapping is in fact necessary here though, since curve bullets are one
|
|
; of the few sprite types with a height greater than PLAYFIELD_Y *and*
|
|
; sometimes leave the playfield through the top. Therefore, their top Y
|
|
; coordinate can and will end up between 0 and -15, before being clipped
|
|
; at -16 (PLAYFIELD_Y - CURVEBULLET_H). curvebullet_put() will then handle
|
|
; the actual Y wrapping of the remaining sprite rows.
|
|
or dx, dx ; (PLAYFIELD_Y - (CURVEBULLET_H / 2))
|
|
jge short @@positive_y
|
|
add dx, RES_Y
|
|
@@positive_y:
|
|
endm
|
|
|
|
push bp
|
|
mov bp, sp
|
|
sub sp, 6
|
|
push si
|
|
push di
|
|
mov [bp+@@head], offset curvebullet_heads
|
|
mov di, offset _curvebullet_trails
|
|
mov ax, GRAM_400
|
|
mov es, ax
|
|
assume es:nothing
|
|
mov [bp+@@bullet_i], 1
|
|
jmp @@bullets_more?
|
|
; ---------------------------------------------------------------------------
|
|
|
|
@@bullet_loop:
|
|
cmp [di+curvebullet_trail_t.flag], 0
|
|
jz @@bullet_next
|
|
mov ah, [di+curvebullet_trail_t.CBT_col]
|
|
call grcg_setcolor_direct_noint_1
|
|
mov si, (CURVEBULLET_TRAIL_NODE_COUNT - 1)
|
|
jmp short @@nodes_more?
|
|
; ---------------------------------------------------------------------------
|
|
|
|
@@node_loop:
|
|
mov bx, si
|
|
mov al, [di+curvebullet_trail_t.node_sprite+bx]
|
|
mov ah, 0
|
|
mov [bp+@@trail_sprite], ax
|
|
shl bx, 2
|
|
mov ax, [di+curvebullet_trail_t.node_pos[bx]+y]
|
|
sar ax, 4
|
|
mov dx, ax
|
|
mov bx, si
|
|
shl bx, 2
|
|
mov ax, [di+curvebullet_trail_t.node_pos[bx]+x]
|
|
sar ax, 4
|
|
@@clip @@node_next
|
|
|
|
@@node_render:
|
|
mov bx, [bp+@@trail_sprite]
|
|
call @curvebullet_put
|
|
|
|
@@node_next:
|
|
; Yes, we only render every second node! You only start to notice jagged
|
|
; edges and gaps between the nodes once their speed exceeds roughly 11
|
|
; pixels per second, which never happens during regular gameplay.
|
|
; https://rec98.nmlgc.net/blog/2020-02-29 has a demo video of how this
|
|
; optimization would look at higher speeds.
|
|
sub si, 2
|
|
|
|
@@nodes_more?:
|
|
or si, si
|
|
jg short @@node_loop
|
|
mov bx, [bp+@@head]
|
|
mov ax, [bx+curvebullet_head_t.pos.cur.y]
|
|
sar ax, 4
|
|
mov dx, ax
|
|
mov ax, [bx+curvebullet_head_t.pos.cur.x]
|
|
sar ax, 4
|
|
@@clip @@bullet_next
|
|
|
|
@@head_render:
|
|
mov bx, [bp+@@head]
|
|
mov bx, [bx+curvebullet_head_t.CBH_sprite]
|
|
call @curvebullet_put
|
|
|
|
@@bullet_next:
|
|
inc [bp+@@bullet_i]
|
|
add [bp+@@head], size curvebullet_head_t
|
|
add di, size curvebullet_trail_t
|
|
|
|
@@bullets_more?:
|
|
cmp [bp+@@bullet_i], 1 + CURVEBULLET_COUNT
|
|
jl @@bullet_loop
|
|
pop di
|
|
pop si
|
|
leave
|
|
retn
|
|
curvebullets_render endp
|