
include ivram.inc



ASCII1_SP_CHECK     equ  2800h
ASCII1_SP_START     equ  2E00h
JAPAN2_SP_START     equ  0E00h

IGNORE_SPRITE       equ  0FFFFh



bseg

s_info      dw  ?       ; スプライト情報(iv_sprite)
s_max       dw  ?       ; スプライトmax
s_overlay   dw  ?       ; 重ねあわせmax
s_vvram     dw  ?       ; 仮想VRAM
s_vvramend  dw  ?       ; 終端 + 1
s_count     dw  ?       ; 登録スプライト数
c_info      dw  IV_CHARTABLE_MAX dup (?) ; キャラクタ情報(iv_charinfo)
c_charmax   dw  IV_CHARTABLE_MAX dup (?) ; テーブル単位の最大キャラ数
c_tables    dd  IV_CHARTABLE_MAX dup (?) ; キャラクタバッファ

endbseg





cseg

;------------------------------------------------------
; void ivs_set_chartable
;   (int tableno, int max, BYTE* info_buf, BYTE far* char_buf);
;------------------------------------------------------
    public _ivs_set_chartable
needeven
_ivs_set_chartable proc near
    center
    mov     bx, [bp + CPARAM1]      ; bx: tableno
    shl     bx, 1                   ; bx: tableno * 2
    mov     ax, [bp + CPARAM2]
    mov     c_charmax[bx], ax
    mov     ax, [bp + CPARAM3]
    mov     c_info[bx], ax
    shl     bx, 1                   ; bx: tableno * 4
    mov     ax, [bp + CPARAM4]
    mov     c_tables[bx].farofs, ax
    mov     ax, [bp + CPARAM5]
    mov     c_tables[bx].farseg, ax
ssct_ret:
    cleave
    ret
_ivs_set_chartable endp



;------------------------------------------------------
; void ivs_sprite_init
;        (BYTE* sprite_buf, int max, BYTE* vvram_buf, int overlay_max);
;------------------------------------------------------
    public _ivs_sprite_init
needeven
_ivs_sprite_init proc near
    center
    mov     ax, [bp + CPARAM1]
    mov     s_info, ax
    mov     ax, [bp + CPARAM2]
    mov     s_max, ax
    mov     ax, [bp + CPARAM3]
    mov     s_vvram, ax
    mov     ax, [bp + CPARAM4]
    cmp     ax, IV_OVERLAY_MIN
    jae     short ssi_10
    mov     ax, IV_OVERLAY_MIN
ssi_10:
    mov     s_overlay, ax

    shl     ax, 1
    mov     bx, IV_CXY
    mul     bx
    add     ax, s_vvram
    mov     s_vvramend, ax

ssi_ret:
    cleave
    ret
_ivs_sprite_init endp


;------------------------------------------------------
; void ivs_start_render(WORD flags);
;------------------------------------------------------
    public  _ivs_start_render
needeven
_ivs_start_render proc near
    center

    mov     s_count, 0

ssr_vclear:
    mov     bx, [bp + CPARAM1]  ; bx: flags
    test    bx, IV_STARTRENDER_NOVRAMINIT
    jnz     short ssr_novclear

    mov     bx, s_vvram
    mov     cx, IV_CXY
    mov     ax, IGNORE_SPRITE
    mov     dx, s_overlay
    shl     dx, 1
ssr_cl10:
    mov     [bx], ax
    add     bx, dx
    loop    ssr_cl10

ssr_novclear:
    
ssr_ret:
    cleave
    ret
_ivs_start_render endp



;------------------------------------------------------
; void ivs_end_render(void);
;------------------------------------------------------
    public _ivs_end_render
needeven
_ivs_end_render proc near
    center
    sub     sp, IV_CHAR_UNITSIZE
    mov     bp, sp              ; bp: render buffer
    push    si
    push    di
    push    es

    mov     si, s_vvram         ; si: vvram pointer
    xor     di, di              ; di: vram pointer

ser_10:    
    mov     cx, s_overlay
ser_20:
    mov     ax, [si]            ; ax: sprite number
    cmp     ax, s_count
    jae     short ser_blt
    cmp     ax, IGNORE_SPRITE
    je      short ser_blt

ser_render:
    push    cx
    push    si
    push    di

    push    ss                  ; es:di: render buffer
    pop     es
    mov     di, bp
    mov     bx, ax
    shl     bx, 2               ; bx: iv_sprite pointer
    add     bx, s_info
    mov     ax, [bx].ivs_param  ; ax: param
    call    [bx].ivs_renderer
    
    pop     di
    pop     si
    pop     cx

    add     si, 2
    loop    ser_20

ser_blt:
    add     si, cx              ; si: next vvram
    add     si, cx
    cmp     cx, s_overlay
    jne     short ser_blt10

ser_noblt:
    add     di, IV_CHAR_UNITSIZE
    jmp     short ser_blt20   

ser_blt10:
    push    si
    push    ds
    xor     ax, ax
    mov     ds, ax
    mov     ax, IV_VRAMSEG
    mov     es, ax
    mov     si, bp
    rept    IV_CHAR_UNITSIZE / 2
        movsw
    endm
    pop     ds
    pop     si

ser_blt20:

    cmp     si, s_vvramend
    jb      short ser_10
    
ser_ret:
    add     bp, IV_CHAR_UNITSIZE
    pop     es
    pop     di
    pop     si
    cleave
    ret
_ivs_end_render endp


;------------------------------------------------------
; void ivs_add_sprite(int charno, int x, int y);
;------------------------------------------------------
    public _ivs_add_sprite
needeven
_ivs_add_sprite proc near
    center
    push    si
    push    di

sas_check:
    mov     ax, s_count
    cmp     ax, s_max
    jae     short sas_ret

sas_xy:
    mov     bl, [bp + CPARAM2]
    mov     bh, [bp + CPARAM3]
    mov     di, bx              ; di: y, x

sas_charinfo:
    mov     si, [bp + CPARAM1]  ; si: charno
    mov     ax, si
    call    get_charinfo
    test    al, IV_CHARINFO_NORENDER
    jnz     short sas_ret
    test    al, IV_CHARINFO_OPAQUE
    jz      short sas_normal

sas_opaque:
    mov     bx, di
    call    get_vvram_address
    jc      short sas_ret
    mov     [bx], IGNORE_SPRITE
    mov     ax, si
    mov     bx, di
    mov     dx, offset cs:render_opaque
    call    ivsa_add_renderer

sas_normal:
    mov     ax, si
    mov     bx, di
    mov     dx, offset cs:render_normal
    call    ivsa_add_renderer

sas_ret:
    pop     di
    pop     si
    cleave
    ret
_ivs_add_sprite endp


;------------------------------------------------------
; void ivs_add_sprite_rect
;        (int charno, int x, int y, int w, int h, int delta);
;------------------------------------------------------
    public _ivs_add_sprite_rect
needeven
_ivs_add_sprite_rect proc near
    center
    push    si                  ; -2
    push    di                  ; -4

sasr_mkstack:
    mov     si, [bp + CPARAM1]  ; si: charno
    mov     ax, [bp + CPARAM2]  ; w += x
    add     [bp + CPARAM4], ax
    push    [bp + CPARAM3]      ; -6  y
    sub     sp, 4               ; -8  x
                                ; -10 charno
sasr_10:
    mov     di, [bp + CPARAM2]  ; di: x
sasr_20:
    mov     [bp - 10], si
    mov     [bp - 8], di
    call    _ivs_add_sprite
    inc     si
    inc     di
    cmp     di, [bp + CPARAM4]
    jl      short sasr_20

    add     si, [bp + CPARAM6]
    inc     word ptr [bp - 6]
    dec     word ptr [bp + CPARAM5]
    jnz     short sasr_10

    add     sp, 6
    pop     di
    pop     si
    cleave
    ret
_ivs_add_sprite_rect endp


;------------------------------------------------------
; void ivs_add_opaque_rect(int charno, int x, int y, int w, int h);
;------------------------------------------------------
    public _ivs_add_opaque_rect
needeven
_ivs_add_opaque_rect proc near
    center
    push    si
    push    di

saor_check:
    mov     ax, [bp + CPARAM4]      ; (w == 0) || (h == 0)
    or      ax, [bp + CPARAM5]
    jz      short saor_ret

saor_counter:
    mov     ax, [bp + CPARAM4]      ; ax: w * h
    mul     word ptr [bp + CPARAM5]
    mov     di, s_max
    sub     di, s_count             ; di: all count
    jbe     short saor_ret
    cmp     ax, di
    ja      short saor_10
    mov     di, ax
saor_10:
    mov     si, [bp + CPARAM1]      ; si: charno
    mov     bh, [bp + CPARAM3]      ; bh: y
saor_20:
    mov     bl, [bp + CPARAM2]      ; bl: x
    mov     cx, [bp + CPARAM4]      ; cx: w
saor_30:
    push    bx
    call    get_vvram_address
    jc      short saor_35
    mov     [bx], IGNORE_SPRITE
saor_35:
    pop     bx

    push    bx
    push    cx
    push    di
    mov     ax, si
    mov     dx, offset cs:render_opaque
    call    ivsa_add_renderer
    pop     di
    pop     cx
    pop     bx
    inc     bl
    dec     di
    jz      saor_ret
    loop    saor_30
    inc     bh
    jmp     short saor_20

saor_ret:
    pop     di
    pop     si
    cleave
    ret
_ivs_add_opaque_rect endp



;------------------------------------------------------
; ivsa_add_renderer -- renderer 追加
;in
; bl, bh: x, y (no clip)
; dx: renderer
; ax: render param
;break
; bx, cx, di
;------------------------------------------------------
    public ivsa_add_renderer
needeven
ivsa_add_renderer proc near

    push    ax                  ; >
    push    dx                  ; >>
    call    get_vvram_address   ; bx: vvram
    jnc     short ar_ok
    add     sp, 4
    ret
ar_ok:
    mov     di, bx              ; di: vvram
    mov     cx, s_overlay
ar_find:
    cmp     [bx], IGNORE_SPRITE
    je      short ar_add
    add     bx, 2
    loop    ar_find

ar_shift:
    mov     bx, di
    add     bx, 2               ; bx: vvram[1]
    mov     cx, s_overlay
    sub     cx, 2               ; cx: s_overlay - 2
ar_shift10:
    mov     ax, [bx + 2]
    mov     [bx], ax
    add     bx, 2
    loop    ar_shift10

ar_add:
    pop     dx                  ; <<
    pop     ax                  ; <

    mov     di, bx              ; di: add point
    mov     bx, s_count
    mov     [di], bx
    shl     bx, 2               ; bx: iv_sprite pointer
    add     bx, s_info
    mov     [bx].ivs_renderer, dx
    mov     [bx].ivs_param, ax

    jcxz    ar_add10
    mov     [di + 2], IGNORE_SPRITE
ar_add10:
    inc     s_count

ar_ret:
    ret
ivsa_add_renderer endp




;------------------------------------------------------
; render_xxx -- renderer
;
;in
; ax: param
; es:di: render buffer
;
; rendererはbp,ds,ssを変更してはならない。
;------------------------------------------------------


;------------------------------------------------------
; render_opaque -- 塗りつぶしキャラクタ
;
;in
; ax: param(charno)
;------------------------------------------------------
needeven
render_opaque proc near
    call    get_chardata        ; dx:si: chardata
    push    ds
    mov     ds, dx
    rept    IV_CHAR_UNITSIZE / 2
        add   si, 2
        movsw
    endm
    pop     ds
    ret
render_opaque endp


;------------------------------------------------------
; render_normal -- 通常のスプライト
;
;in
; ax: param(charno)
;------------------------------------------------------
needeven
render_normal proc near
    call    get_chardata        ; dx:si: chardata
    push    ds
    mov     ds, dx
    rept    IV_CHAR_UNITSIZE / 2
        lodsw
        and   ax, es:[di]
        mov   bx, ax
        lodsw
        or    ax, bx
        stosw
    endm
    pop     ds
    ret
render_normal endp


;------------------------------------------------------
; render_fill_line -- ラインパターン塗りつぶし
;
;in
; ax: param(pattern)
;------------------------------------------------------
needeven
render_fill_line proc near
    rept    IV_CHAR_UNITSIZE / 2
        stosw
    endm
    ret
render_fill_line endp





;------------------------------------------------------
; get_vram_address -- VRAMアドレス算出
;
;in
; bl, bh: x, y
;out
; bx(ax): address
;------------------------------------------------------
needeven
get_vram_address proc near
    mov     al, IV_CX       ; ax: y*IV_CX
    mul     bh
    xor     bh, bh
    add     ax, bx          ; ax: +x
    shl     ax, 4           ; ax: *IV_CHAR_UNITSIZE
    mov     bx, ax
    ret
get_vram_address endp


;------------------------------------------------------
; get_vvram_address -- 仮想VRAMアドレス算出
;
;in
; bl, bh: x, y
;out
; cf: clipped
; bx(ax): address
;break
; dx
;------------------------------------------------------
needeven
get_vvram_address proc near

gvva_check:
    test    bl, bl
    js      short gvva_clip
    test    bh, bh
    js      short gvva_clip
    cmp     bl, IV_CX
    jae     short gvva_clip
    cmp     bh, IV_CY
    jb      short gvva_noclip
gvva_clip:
    stc
    ret

gvva_noclip:
    mov     al, IV_CX       ; ax: y*IV_CX
    mul     bh
    xor     bh, bh
    add     ax, bx          ; ax: +x
    mov     bx, s_overlay
    shl     bx, 1
    mul     bx
    add     ax, s_vvram     ; no need 'clc'
    mov     bx, ax
    ret
get_vvram_address endp



;------------------------------------------------------
; get_chardata -- キャラデータ
;
;in
; ax: charno
;out
; dx:si: pointer
;break
; ax, bx, cx
;------------------------------------------------------
needeven
get_chardata proc near
    call    get_ctable_index
    shl     bx, 1
    mov     si, cx
    shl     si, 5               ; si: *IV_CHAR_UNITSIZE*2
    add     si, c_tables[bx].farofs
    mov     dx, c_tables[bx].farseg
    ret
get_chardata endp


;------------------------------------------------------
; get_charinfo -- charinfo取得
;
;in
; ax: charno
;out
; al: charinfo
;break
; bx, cx, dx
;------------------------------------------------------
needeven
get_charinfo proc near
    call    get_ctable_index
    mov     bx, c_info[bx]
    add     bx, cx
    mov     al, [bx]
    ret
get_charinfo endp


;------------------------------------------------------
; get_ctable_index -- charno からテーブルインデックス算出
;
;in
; ax: charno
;out
; bx: テーブルインデックス*2
; cx: テーブル中でのインデックス
;break
; dx
;------------------------------------------------------
needeven
get_ctable_index proc near
    mov     cx, ax
    xor     bx, bx
gci_loop:
    mov     dx, c_charmax[bx]
    cmp     cx, dx
    jb      short gci_found
    sub     cx, dx
    add     bx, 2
    jmp     short gci_loop
gci_found:
    ret
get_ctable_index endp



;------------------------------------------------------
; void iv_adjust_sp() -- SP補正によるIRAM確保
; 注意：現在は使用していない。
;------------------------------------------------------
    public  _iv_adjust_sp
needeven
_iv_adjust_sp proc near

    ; ASCII1かどうかをSPでチェック
    mov     ax, sp
    cmp     ax, ASCII1_SP_CHECK
    ja      short aasp_ok

aasp_ng:
    panic   IV_PANIC_INVALIDSP

aasp_ok:
    push    si
    push    di
    push    es
    mov     ax, ss
    mov     es, ax

    mov     cx, ASCII1_SP_START
    sub     cx, sp
    mov     di, JAPAN2_SP_START
    sub     di, cx
    mov     bx, di
    mov     si, ASCII1_SP_START
    sub     si, cx
    shr     cx, 1
    rep     movs word ptr es:[di], es:[si]

    mov     sp, bx
    
    pop     es
    pop     di
    pop     si
    sub     bp, ASCII1_SP_START - JAPAN2_SP_START

aasp_ret:
    ret

_iv_adjust_sp endp




endcseg










end
