.setcpu "6502" .include "apple2.inc" .include "../inc/apple2.inc" .include "../inc/prodos.inc" .include "mgtk.inc" .include "../inc/macros.inc" ;;; ============================================================ ;;; MouseGraphics ToolKit ;;; ============================================================ .proc mgtk .org $4000 screen_width := 560 screen_height := 192 ;;; ============================================================ ;;; ZP Usage params_addr := $80 ;; $8A initialized same way as current port (see $01 IMPL) ;; $A8 - Menu count ;; $A9-$AA - Address of current winfo ;; $AB-... - Copy of first 12 bytes of current winfo ;; $D0-$F3 - Current GrafPort ;; $D0-$DF - portmap ;; $D0-D3 - viewloc (x/y words) ;; $D4-D5 - mapbits - screen address = $2000 ;; $D6-D7 - mapwidth - screen stride = $80 ;; $D8-DF - maprect (x1/y1/x2/y2) ;; $E0-$E7 - penpattern ;; $E8-$E9 - colormasks (AND, OR) ;; $EA-$ED - penloc (x/y words) ;; $EE-$EF - penwidth/penheight ;; $F0 - penmode ;; $F1 - textback ;; $F2-$F3 - textfont ;; $F4-$F5 - Active port (???) ;; $F6-$FA - fill_eor_mask/x_offset/y_offset ;; $FB-$FC - glyph widths ;; $FD - font type (0=regular, $80=double width) ;; $FE - last glyph index (count is this + 1) ;; $FF - glyph height current_grafport := $D0 current_portmap := $D0 current_viewloc_x := $D0 current_viewloc_y := $D2 current_mapbits := $D4 current_mapwidth := $D6 current_maprect_x1 := $D8 current_maprect_y1 := $DA current_maprect_x2 := $DC current_maprect_y2 := $DE current_penpattern := $E0 current_colormasks := $E8 current_colormask_and := $E8 current_colormasks_or := $E9 current_penloc := $EA current_penloc_x := $EA current_penloc_y := $EC current_pensize := $EE current_penwidth := $EE current_penheight := $EF current_penmode := $F0 current_textback := $F1 current_textfont := $F2 active_port := $F4 ; address of live port block fill_eor_mask := $F6 x_offset := $F7 y_offset := $F9 glyph_widths := $FB ; address glyph_type := $FD ; 0=regular, $80=double width glyph_last := $FE ; last glyph index glyph_height_p := $FF ; glyph height ;;; ============================================================ ;;; MGTK .proc dispatch .assert * = MGTK::MLI, error, "Entry point must be at $4000" lda LOWSCR sta SET80COL bit preserve_zp_flag ; save ZP? bpl adjust_stack ;; Save $80...$FF, swap in what MGTK needs at $F4...$FF COPY_BYTES $80, $80, zp_saved COPY_BYTES $C, active_saved, active_port jsr apply_active_port_to_port adjust_stack: ; Adjust stack to account for params pla ; and stash address at params_addr. sta params_addr clc adc #<3 tax pla sta params_addr+1 adc #>3 pha txa pha tsx stx stack_ptr_stash ldy #1 ; Command index lda (params_addr),y asl a tax copy16 jump_table,x, jump_addr iny ; Point params_addr at params lda (params_addr),y pha iny lda (params_addr),y sta params_addr+1 pla sta params_addr ;; Param length format is a byte pair; ;; * first byte is ZP address to copy bytes to ;; * second byte's high bit is "hide cursor" flag ;; * rest of second byte is # bytes to copy ldy param_lengths+1,x ; Check param length... bpl done_hiding txa ; if high bit was set, stash pha ; registers and params_addr and then tya ; optionally hide cursor pha lda params_addr pha lda params_addr+1 pha bit desktop_initialized_flag bpl :+ jsr hide_cursor : pla sta params_addr+1 pla sta params_addr pla and #$7F ; clear high bit in length count tay pla tax done_hiding: lda param_lengths,x ; ZP offset for params beq jump ; nothing to copy sta store+1 dey : lda (params_addr),y store: sta $FF,y ; self modified dey bpl :- jump_addr := *+1 jump: jsr $FFFF ; the actual call ;; Exposed for routines to call directly cleanup: bit desktop_initialized_flag bpl :+ jsr show_cursor : bit preserve_zp_flag bpl exit_with_0 jsr apply_port_to_active_port COPY_BYTES $C, active_port, active_saved COPY_BYTES $80, zp_saved, $80 ;; default is to return with A=0 exit_with_0: lda #0 rts1: rts .endproc ;;; ============================================================ ;;; Routines can jmp here to exit with A set exit_with_a: pha jsr dispatch::cleanup pla ldx stack_ptr_stash txs ldy #$FF rts2: rts ;; TODO: Macro for exit_with_a .macro exit_call arg lda #arg jmp exit_with_a .endmacro ;;; ============================================================ ;;; Copy port params (36 bytes) to/from active port addr .proc apply_active_port_to_port ldy #.sizeof(MGTK::GrafPort)-1 : lda (active_port),y sta current_grafport,y dey bpl :- rts .endproc .proc apply_port_to_active_port ldy #.sizeof(MGTK::GrafPort)-1 : lda current_grafport,y sta (active_port),y dey bpl :- rts .endproc ;;; ============================================================ ;;; Drawing calls show/hide cursor before/after ;;; A recursion count is kept to allow rentrancy. hide_cursor_count: .byte 0 .proc hide_cursor dec hide_cursor_count jmp HideCursorImpl .endproc .proc show_cursor bit hide_cursor_count bpl rts2 inc hide_cursor_count jmp ShowCursorImpl .endproc ;;; ============================================================ ;;; Jump table for MGTK entry point calls ;; jt_rts can be used if the only thing the ;; routine needs to do is copy params into ;; the zero page (port) jt_rts := dispatch::rts1 jump_table: .addr jt_rts ; $00 NoOp ;; ---------------------------------------- ;; Graphics Primitives ;; Initialization Commands .addr InitGrafImpl ; $01 InitGraf .addr SetSwitchesImpl ; $02 SetSwitches ;; GrafPort Commands .addr InitPortImpl ; $03 InitPort .addr SetPortImpl ; $04 SetPort .addr GetPortImpl ; $05 GetPort .addr SetPortBitsImpl ; $06 SetPortBits .addr SetPenModeImpl ; $07 SetPenMode .addr SetPatternImpl ; $08 SetPattern .addr jt_rts ; $09 SetColorMasks .addr jt_rts ; $0A SetPenSize .addr SetFontImpl ; $0B SetFont .addr jt_rts ; $0C SetTextBG ;; Drawing Commands .addr MoveImpl ; $0D Move .addr jt_rts ; $0E MoveTo .addr LineImpl ; $0F Line .addr LineToImpl ; $10 LineTo .addr PaintRectImpl ; $11 PaintRect .addr FrameRectImpl ; $12 FrameRect .addr InRectImpl ; $13 InRect .addr PaintBitsImpl ; $14 PaintBits .addr PaintPolyImpl ; $15 PaintPoly .addr FramePolyImpl ; $16 FramePoly .addr InPolyImpl ; $17 InPoly ;; Text Commands .addr TextWidthImpl ; $18 TextWidth .addr DrawTextImpl ; $19 DrawText ;; Utility Commands .addr SetZP1Impl ; $1A SetZP1 .addr SetZP2Impl ; $1B SetZP2 .addr VersionImpl ; $1C Version ;; ---------------------------------------- ;; MouseGraphics ToolKit ;; Initialization Calls .addr StartDeskTopImpl ; $1D StartDeskTop .addr StopDeskTopImpl ; $1E StopDeskTop .addr SetUserHookImpl ; $1F SetUserHook .addr AttachDriverImpl ; $20 AttachDriver .addr ScaleMouseImpl ; $21 ScaleMouseImpl .addr KeyboardMouse ; $22 KeyboardMouse .addr GetIntHandlerImpl ; $23 GetIntHandler ;; Cursor Manager Calls .addr SetCursorImpl ; $24 SetCursor .addr ShowCursorImpl ; $25 ShowCursor .addr HideCursorImpl ; $26 HideCursor .addr ObscureCursorImpl ; $27 ObscureCursor .addr GetCursorAddrImpl ; $28 GetCursorAddr ;; Event Manager Calls .addr CheckEventsImpl ; $29 CheckEvents .addr GetEventImpl ; $2A GetEvent .addr FlushEventsImpl ; $2B FlushEvents .addr PeekEventImpl ; $2C PeekEvent .addr PostEventImpl ; $2D PostEvent .addr SetKeyEventImpl ; $2E SetKeyEvent ;; Menu Manager Calls .addr InitMenuImpl ; $2F InitMenu .addr SetMenuImpl ; $30 SetMenu .addr MenuSelectImpl ; $31 MenuSelect .addr MenuKeyImpl ; $32 MenuKey .addr HiliteMenuImpl ; $33 HiliteMenu .addr DisableMenuImpl ; $34 DisableMenu .addr DisableItemImpl ; $35 DisableItem .addr CheckItemImpl ; $36 CheckItem .addr SetMarkImpl ; $37 SetMark ;; Window Manager Calls .addr OpenWindowImpl ; $38 OpenWindow .addr CloseWindowImpl ; $39 CloseWindow .addr CloseAllImpl ; $3A CloseAll .addr GetWinPtrImpl ; $3B GetWinPtr .addr GetWinPortImpl ; $3C GetWinPort .addr SetWinPortImpl ; $3D SetWinPort .addr BeginUpdateImpl ; $3E BeginUpdate .addr EndUpdateImpl ; $3F EndUpdate .addr FindWindowImpl ; $40 FindWindow .addr FrontWindowImpl ; $41 FrontWindow .addr SelectWindowImpl ; $42 SelectWindow .addr TrackGoAwayImpl ; $43 TrackGoAway .addr DragWindowImpl ; $44 DragWindow .addr GrowWindowImpl ; $45 GrowWindow .addr ScreenToWindowImpl ; $46 ScreenToWindow .addr WindowToScreenImpl ; $47 WindowToScreenImpl ;; Control Manager Calls .addr FindControlImpl ; $48 FindControl .addr SetCtlMaxImpl ; $49 SetCtlMax .addr TrackThumbImpl ; $4A TrackThumb .addr UpdateThumbImpl ; $4B UpdateThumb .addr ActivateCtlImpl ; $4C ActivateCtl ;; Extra Calls .addr BitBltImpl ; $4D BitBlt .addr SetMenuSelectionImpl; $4E SetMenuSelection .addr GetDeskPatImpl ; $4F GetDeskPat .addr SetDeskPatImpl ; $50 SetDeskPat .addr DrawMenuImpl ; $51 DrawMenu ;; Entry point param lengths ;; (length, ZP destination, hide cursor flag) param_lengths: .macro PARAM_DEFN length, zp, cursor .byte zp, ((length) | ((cursor) << 7)) .endmacro ;; ---------------------------------------- ;; Graphics Primitives PARAM_DEFN 0, $00, 0 ; $00 NoOp ;; Initialization PARAM_DEFN 0, $00, 0 ; $01 InitGraf PARAM_DEFN 1, $82, 0 ; $02 SetSwitches ;; GrafPort PARAM_DEFN 0, $00, 0 ; $03 InitPort PARAM_DEFN 36, current_grafport, 0 ; $04 SetPort PARAM_DEFN 0, $00, 0 ; $05 GetPort PARAM_DEFN 16, current_portmap, 0 ; $06 SetPortBits PARAM_DEFN 1, current_penmode, 0 ; $07 SetPenMode PARAM_DEFN 8, current_penpattern, 0 ; $08 SetPattern PARAM_DEFN 2, current_colormasks, 0 ; $09 SetColorMasks PARAM_DEFN 2, current_pensize, 0 ; $0A SetPenSize PARAM_DEFN 0, $00, 0 ; $0B SetFont PARAM_DEFN 1, current_textback, 0 ; $0C SetTextBG ;; Drawing PARAM_DEFN 4, $A1, 0 ; $0D Move PARAM_DEFN 4, current_penloc, 0 ; $0E MoveTo PARAM_DEFN 4, $A1, 1 ; $0F Line PARAM_DEFN 4, $92, 1 ; $10 LineTo PARAM_DEFN 8, $92, 1 ; $11 PaintRect PARAM_DEFN 8, $9F, 1 ; $12 FrameRect PARAM_DEFN 8, $92, 0 ; $13 InRect PARAM_DEFN 16, $8A, 0 ; $14 PaintBits PARAM_DEFN 0, $00, 1 ; $15 PaintPoly PARAM_DEFN 0, $00, 1 ; $16 FramePoly PARAM_DEFN 0, $00, 0 ; $17 InPoly ;; Text PARAM_DEFN 3, $A1, 0 ; $18 TextWidth PARAM_DEFN 3, $A1, 1 ; $19 DrawText ;; Utility PARAM_DEFN 1, $82, 0 ; $1A SetZP1 PARAM_DEFN 1, $82, 0 ; $1B SetZP2 PARAM_DEFN 0, $00, 0 ; $1C Version ;; ---------------------------------------- ;; MouseGraphics ToolKit Calls ;; Initialization PARAM_DEFN 12, $82, 0 ; $1D StartDeskTop PARAM_DEFN 0, $00, 0 ; $1E StopDeskTop PARAM_DEFN 3, $82, 0 ; $1F SetUserHook PARAM_DEFN 2, $82, 0 ; $20 AttachDriver PARAM_DEFN 2, $82, 0 ; $21 ScaleMouse PARAM_DEFN 0, $00, 0 ; $22 KeyboardMouse PARAM_DEFN 0, $00, 0 ; $23 GetIntHandler ;; Cursor Manager PARAM_DEFN 0, $00, 0 ; $24 SetCursor PARAM_DEFN 0, $00, 0 ; $25 ShowCursor PARAM_DEFN 0, $00, 0 ; $26 HideCursor PARAM_DEFN 0, $00, 0 ; $27 ObscureCursor PARAM_DEFN 0, $00, 0 ; $28 GetCursorAddr ;; Event Manager PARAM_DEFN 0, $00, 0 ; $29 CheckEvents PARAM_DEFN 0, $00, 0 ; $2A GetEvent PARAM_DEFN 0, $00, 0 ; $2B FlushEvents PARAM_DEFN 0, $00, 0 ; $2C PeekEvent PARAM_DEFN 5, $82, 0 ; $2D PostEvent PARAM_DEFN 1, $82, 0 ; $2E SetKeyEvent ;; Menu Manager PARAM_DEFN 4, $82, 0 ; $2F InitMenu PARAM_DEFN 0, $00, 0 ; $30 SetMenu PARAM_DEFN 0, $00, 0 ; $31 MenuSelect PARAM_DEFN 4, $C7, 0 ; $32 MenuKey PARAM_DEFN 1, $C7, 0 ; $33 HiliteMenu PARAM_DEFN 2, $C7, 0 ; $34 DisableMenu PARAM_DEFN 3, $C7, 0 ; $35 DisableItem PARAM_DEFN 3, $C7, 0 ; $36 CheckItem PARAM_DEFN 4, $C7, 0 ; $37 SetMark ;; Window Manager PARAM_DEFN 0, $00, 0 ; $38 OpenWindow PARAM_DEFN 1, $82, 0 ; $39 CloseWindow PARAM_DEFN 0, $00, 0 ; $3A CloseAll PARAM_DEFN 1, $82, 0 ; $3B GetWinPtr PARAM_DEFN 3, $82, 0 ; $3C GetWinPort PARAM_DEFN 2, $82, 0 ; $3D SetWinPort PARAM_DEFN 1, $82, 0 ; $3E BeginUpdate PARAM_DEFN 1, $82, 0 ; $3F EndUpdate PARAM_DEFN 4, current_penloc, 0 ; $40 FindWindow PARAM_DEFN 0, $00, 0 ; $41 FrontWindow PARAM_DEFN 1, $82, 0 ; $42 SelectWindow PARAM_DEFN 0, $00, 0 ; $43 TrackGoAway PARAM_DEFN 5, $82, 0 ; $44 DragWindow PARAM_DEFN 5, $82, 0 ; $45 GrowWindow PARAM_DEFN 5, $82, 0 ; $46 ScreenToWindow PARAM_DEFN 5, $82, 0 ; $47 WindowToScreen ;; Control Manager PARAM_DEFN 4, current_penloc, 0 ; $48 FindControl PARAM_DEFN 2, $82, 0 ; $49 SetCtlMax PARAM_DEFN 5, $82, 0 ; $4A TrackThumb PARAM_DEFN 2, $8C, 0 ; $4B UpdateThumb PARAM_DEFN 2, $8C, 0 ; $4C ActivateCtl ;; Extra Calls PARAM_DEFN 16, $8A, 0 ; $4D BitBlt PARAM_DEFN 2, $82, 0 ; $4E SetMenuSelection PARAM_DEFN 0, $00, 0 ; $4F GetDeskPat PARAM_DEFN 0, $00, 0 ; $50 SetDeskPat PARAM_DEFN 0, $00, 0 ; $51 DrawMenu ;;; ============================================================ ;;; Pre-Shift Tables shift_1_aux: .byte $00,$02,$04,$06,$08,$0A,$0C,$0E .byte $10,$12,$14,$16,$18,$1A,$1C,$1E .byte $20,$22,$24,$26,$28,$2A,$2C,$2E .byte $30,$32,$34,$36,$38,$3A,$3C,$3E .byte $40,$42,$44,$46,$48,$4A,$4C,$4E .byte $50,$52,$54,$56,$58,$5A,$5C,$5E .byte $60,$62,$64,$66,$68,$6A,$6C,$6E .byte $70,$72,$74,$76,$78,$7A,$7C,$7E .byte $00,$02,$04,$06,$08,$0A,$0C,$0E .byte $10,$12,$14,$16,$18,$1A,$1C,$1E .byte $20,$22,$24,$26,$28,$2A,$2C,$2E .byte $30,$32,$34,$36,$38,$3A,$3C,$3E .byte $40,$42,$44,$46,$48,$4A,$4C,$4E .byte $50,$52,$54,$56,$58,$5A,$5C,$5E .byte $60,$62,$64,$66,$68,$6A,$6C,$6E .byte $70,$72,$74,$76,$78,$7A,$7C,$7E shift_1_main: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 shift_2_aux: .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $20,$24,$28,$2C,$30,$34,$38,$3C .byte $40,$44,$48,$4C,$50,$54,$58,$5C .byte $60,$64,$68,$6C,$70,$74,$78,$7C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $20,$24,$28,$2C,$30,$34,$38,$3C .byte $40,$44,$48,$4C,$50,$54,$58,$5C .byte $60,$64,$68,$6C,$70,$74,$78,$7C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $20,$24,$28,$2C,$30,$34,$38,$3C .byte $40,$44,$48,$4C,$50,$54,$58,$5C .byte $60,$64,$68,$6C,$70,$74,$78,$7C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $20,$24,$28,$2C,$30,$34,$38,$3C .byte $40,$44,$48,$4C,$50,$54,$58,$5C .byte $60,$64,$68,$6C,$70,$74,$78,$7C shift_2_main: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $03,$03,$03,$03,$03,$03,$03,$03 shift_3_aux: .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 .byte $00,$08,$10,$18,$20,$28,$30,$38 .byte $40,$48,$50,$58,$60,$68,$70,$78 shift_3_main: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $04,$04,$04,$04,$04,$04,$04,$04 .byte $04,$04,$04,$04,$04,$04,$04,$04 .byte $05,$05,$05,$05,$05,$05,$05,$05 .byte $05,$05,$05,$05,$05,$05,$05,$05 .byte $06,$06,$06,$06,$06,$06,$06,$06 .byte $06,$06,$06,$06,$06,$06,$06,$06 .byte $07,$07,$07,$07,$07,$07,$07,$07 .byte $07,$07,$07,$07,$07,$07,$07,$07 shift_4_aux: .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 .byte $00,$10,$20,$30,$40,$50,$60,$70 shift_4_main: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $01,$01,$01,$01,$01,$01,$01,$01 .byte $02,$02,$02,$02,$02,$02,$02,$02 .byte $03,$03,$03,$03,$03,$03,$03,$03 .byte $04,$04,$04,$04,$04,$04,$04,$04 .byte $05,$05,$05,$05,$05,$05,$05,$05 .byte $06,$06,$06,$06,$06,$06,$06,$06 .byte $07,$07,$07,$07,$07,$07,$07,$07 .byte $08,$08,$08,$08,$08,$08,$08,$08 .byte $09,$09,$09,$09,$09,$09,$09,$09 .byte $0A,$0A,$0A,$0A,$0A,$0A,$0A,$0A .byte $0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B .byte $0C,$0C,$0C,$0C,$0C,$0C,$0C,$0C .byte $0D,$0D,$0D,$0D,$0D,$0D,$0D,$0D .byte $0E,$0E,$0E,$0E,$0E,$0E,$0E,$0E .byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F shift_5_aux: .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 .byte $00,$20,$40,$60,$00,$20,$40,$60 shift_5_main: .byte $00,$00,$00,$00,$01,$01,$01,$01 .byte $02,$02,$02,$02,$03,$03,$03,$03 .byte $04,$04,$04,$04,$05,$05,$05,$05 .byte $06,$06,$06,$06,$07,$07,$07,$07 .byte $08,$08,$08,$08,$09,$09,$09,$09 .byte $0A,$0A,$0A,$0A,$0B,$0B,$0B,$0B .byte $0C,$0C,$0C,$0C,$0D,$0D,$0D,$0D .byte $0E,$0E,$0E,$0E,$0F,$0F,$0F,$0F .byte $10,$10,$10,$10,$11,$11,$11,$11 .byte $12,$12,$12,$12,$13,$13,$13,$13 .byte $14,$14,$14,$14,$15,$15,$15,$15 .byte $16,$16,$16,$16,$17,$17,$17,$17 .byte $18,$18,$18,$18,$19,$19,$19,$19 .byte $1A,$1A,$1A,$1A,$1B,$1B,$1B,$1B .byte $1C,$1C,$1C,$1C,$1D,$1D,$1D,$1D .byte $1E,$1E,$1E,$1E,$1F,$1F,$1F,$1F shift_6_aux: .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 .byte $00,$40,$00,$40,$00,$40,$00,$40 shift_6_main: .byte $00,$00,$01,$01,$02,$02,$03,$03 .byte $04,$04,$05,$05,$06,$06,$07,$07 .byte $08,$08,$09,$09,$0A,$0A,$0B,$0B .byte $0C,$0C,$0D,$0D,$0E,$0E,$0F,$0F .byte $10,$10,$11,$11,$12,$12,$13,$13 .byte $14,$14,$15,$15,$16,$16,$17,$17 .byte $18,$18,$19,$19,$1A,$1A,$1B,$1B .byte $1C,$1C,$1D,$1D,$1E,$1E,$1F,$1F .byte $20,$20,$21,$21,$22,$22,$23,$23 .byte $24,$24,$25,$25,$26,$26,$27,$27 .byte $28,$28,$29,$29,$2A,$2A,$2B,$2B .byte $2C,$2C,$2D,$2D,$2E,$2E,$2F,$2F .byte $30,$30,$31,$31,$32,$32,$33,$33 .byte $34,$34,$35,$35,$36,$36,$37,$37 .byte $38,$38,$39,$39,$3A,$3A,$3B,$3B .byte $3C,$3C,$3D,$3D,$3E,$3E,$3F,$3F div7_table: .byte $00,$00,$00,$00,$00,$00,$00 .byte $01,$01,$01,$01,$01,$01,$01,$02 .byte $02,$02,$02,$02,$02,$02,$03,$03 .byte $03,$03,$03,$03,$03,$04,$04,$04 .byte $04,$04,$04,$04,$05,$05,$05,$05 .byte $05,$05,$05,$06,$06,$06,$06,$06 .byte $06,$06,$07,$07,$07,$07,$07,$07 .byte $07,$08,$08,$08,$08,$08,$08,$08 .byte $09,$09,$09,$09,$09,$09,$09,$0A .byte $0A,$0A,$0A,$0A,$0A,$0A,$0B,$0B .byte $0B,$0B,$0B,$0B,$0B,$0C,$0C,$0C .byte $0C,$0C,$0C,$0C,$0D,$0D,$0D,$0D .byte $0D,$0D,$0D,$0E,$0E,$0E,$0E,$0E .byte $0E,$0E,$0F,$0F,$0F,$0F,$0F,$0F .byte $0F,$10,$10,$10,$10,$10,$10,$10 .byte $11,$11,$11,$11,$11,$11,$11,$12 .byte $12,$12,$12,$12,$12,$12,$13,$13 .byte $13,$13,$13,$13,$13,$14,$14,$14 .byte $14,$14,$14,$14,$15,$15,$15,$15 .byte $15,$15,$15,$16,$16,$16,$16,$16 .byte $16,$16,$17,$17,$17,$17,$17,$17 .byte $17,$18,$18,$18,$18,$18,$18,$18 .byte $19,$19,$19,$19,$19,$19,$19,$1A .byte $1A,$1A,$1A,$1A,$1A,$1A,$1B,$1B .byte $1B,$1B,$1B,$1B,$1B,$1C,$1C,$1C .byte $1C,$1C,$1C,$1C,$1D,$1D,$1D,$1D .byte $1D,$1D,$1D,$1E,$1E,$1E,$1E,$1E .byte $1E,$1E,$1F,$1F,$1F,$1F,$1F,$1F .byte $1F,$20,$20,$20,$20,$20,$20,$20 .byte $21,$21,$21,$21,$21,$21,$21,$22 .byte $22,$22,$22,$22,$22,$22,$23,$23 .byte $23,$23,$23,$23,$23,$24,$24,$24 .byte $24 mod7_table: .byte $00,$01,$02,$03 .byte $04,$05,$06,$00,$01,$02,$03,$04 .byte $05,$06,$00,$01,$02,$03,$04,$05 .byte $06,$00,$01,$02,$03,$04,$05,$06 .byte $00,$01,$02,$03,$04,$05,$06,$00 .byte $01,$02,$03,$04,$05,$06,$00,$01 .byte $02,$03,$04,$05,$06,$00,$01,$02 .byte $03,$04,$05,$06,$00,$01,$02,$03 .byte $04,$05,$06,$00,$01,$02,$03,$04 .byte $05,$06,$00,$01,$02,$03,$04,$05 .byte $06,$00,$01,$02,$03,$04,$05,$06 .byte $00,$01,$02,$03,$04,$05,$06,$00 .byte $01,$02,$03,$04,$05,$06,$00,$01 .byte $02,$03,$04,$05,$06,$00,$01,$02 .byte $03,$04,$05,$06,$00,$01,$02,$03 .byte $04,$05,$06,$00,$01,$02,$03,$04 .byte $05,$06,$00,$01,$02,$03,$04,$05 .byte $06,$00,$01,$02,$03,$04,$05,$06 .byte $00,$01,$02,$03,$04,$05,$06,$00 .byte $01,$02,$03,$04,$05,$06,$00,$01 .byte $02,$03,$04,$05,$06,$00,$01,$02 .byte $03,$04,$05,$06,$00,$01,$02,$03 .byte $04,$05,$06,$00,$01,$02,$03,$04 .byte $05,$06,$00,$01,$02,$03,$04,$05 .byte $06,$00,$01,$02,$03,$04,$05,$06 .byte $00,$01,$02,$03,$04,$05,$06,$00 .byte $01,$02,$03,$04,$05,$06,$00,$01 .byte $02,$03,$04,$05,$06,$00,$01,$02 .byte $03,$04,$05,$06,$00,$01,$02,$03 .byte $04,$05,$06,$00,$01,$02,$03,$04 .byte $05,$06,$00,$01,$02,$03,$04,$05 .byte $06,$00,$01,$02,$03,$04,$05,$06 .byte $00,$01,$02,$03 ;;; ============================================================ hires_table_lo: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $80,$80,$80,$80,$80,$80,$80,$80 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $80,$80,$80,$80,$80,$80,$80,$80 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $80,$80,$80,$80,$80,$80,$80,$80 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $80,$80,$80,$80,$80,$80,$80,$80 .byte $28,$28,$28,$28,$28,$28,$28,$28 .byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 .byte $28,$28,$28,$28,$28,$28,$28,$28 .byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 .byte $28,$28,$28,$28,$28,$28,$28,$28 .byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 .byte $28,$28,$28,$28,$28,$28,$28,$28 .byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 .byte $50,$50,$50,$50,$50,$50,$50,$50 .byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 .byte $50,$50,$50,$50,$50,$50,$50,$50 .byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 .byte $50,$50,$50,$50,$50,$50,$50,$50 .byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 .byte $50,$50,$50,$50,$50,$50,$50,$50 .byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 hires_table_hi: .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $00,$04,$08,$0C,$10,$14,$18,$1C .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $01,$05,$09,$0D,$11,$15,$19,$1D .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $02,$06,$0A,$0E,$12,$16,$1A,$1E .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F .byte $03,$07,$0B,$0F,$13,$17,$1B,$1F ;;; ============================================================ ;;; Routines called during PaintRect etc based on ;;; current_penmode ;; ZP usage src_addr := $82 ; pointer to source bitmap vid_addr := $84 ; pointer to video memory left_bytes := $86 ; offset of leftmost coordinate in chars (0-39) bits_addr := $8E ; pointer to pattern/bitmap left_mod14 := $87 ; starting x-coordinate mod 14 left_sidemask := $88 ; bitmask applied to clip left edge of rect right_sidemask := $89 ; bitmask applied to clip right edge of rect src_y_coord := $8C src_mapwidth := $90 ; source stride; $80 = DHGR layout width_bytes := $91 ; width of rectangle in chars left_masks_table := $92 ; bitmasks for left edge indexed by page (0=main, 1=aux) right_masks_table := $96 ; bitmasks for right edge indexed by page (0=main, 1=aux) top := $94 ; top/starting/current y-coordinate bottom := $98 ; bottom/ending/maximum y-coordinate left := $92 right := $96 fixed_div_dividend := $A1 ; parameters used by fixed_div proc fixed_div_divisor := $A3 fixed_div_quotient := $9F ; fixed 16.16 format ;; Text page usage (main/aux) pattern_buffer := $0400 ; buffer for currently selected pattern (page-aligned) bitmap_buffer := $0601 ; scratchpad area for drawing bitmaps/patterns poly_maxima_links := $0428 poly_maxima_prev_vertex := $0468 poly_maxima_next_vertex := $04A8 poly_maxima_slope0 := $0528 poly_maxima_slope1 := $04E8 poly_maxima_slope2 := $0568 poly_maxima_slope3 := $05A8 poly_maxima_yl_table := $05E8 poly_vertex_prev_link := $0680 poly_vertex_next_link := $06BC poly_xl_buffer := $0700 poly_xh_buffer := $073C poly_yl_buffer := $0780 poly_yh_buffer := $07BC .assert pattern_buffer adc #0 sta src_addr+1 jmp dhgr_get_srcbits::get_bits .endproc ;; Start a fill targeting the DHGR screen. .proc dhgr_start_fill txa ; pattern y-offset ror a ror a ror a and #$C0 ; to high 2 bits ora left_bytes sta bits_addr lda #>pattern_buffer adc #0 sta bits_addr+1 next_line_jmp_addr := *+1 jmp dhgr_next_line .endproc ;; Advance to the next line and fill (non-display bitmap ;; destination.) .proc ndbm_next_line lda vid_addr clc adc current_mapwidth sta vid_addr bcc :+ inc vid_addr+1 clc : ldy width_bytes jsr fillmode_jmp jmp fill_next_line .endproc ;; Set vid_addr for the next line and fill (DHGR destination.) .proc dhgr_next_line lda hires_table_hi,x ora current_mapbits+1 sta vid_addr+1 lda hires_table_lo,x clc adc left_bytes sta vid_addr ldy #1 ; aux mem jsr dhgr_fill_line ldy #0 ; main mem jsr dhgr_fill_line jmp fill_next_line .endproc ;; Fill one line in either main or aux screen memory. .proc dhgr_fill_line sta LOWSCR,y lda left_masks_table,y ora #$80 sta left_sidemask lda right_masks_table,y ora #$80 sta right_sidemask ldy width_bytes ;; Fall-through .endproc fillmode_jmp: jmp fillmode_copy ; modified with fillmode routine ;; Address of jump used when drawing from a pattern rather than ;; source data bits. no_srcbits_addr: .addr start_fill_jmp main_right_masks: .byte $00,$00,$00,$00,$00,$00,$00 aux_right_masks: .byte $01,$03,$07,$0F,$1F,$3F,$7F main_left_masks: .byte $7F,$7F,$7F,$7F,$7F,$7F,$7F aux_left_masks: .byte $7F,$7E,$7C,$78,$70,$60,$40 .byte $00,$00,$00,$00,$00,$00,$00 ;; Tables used for fill modes ; Fill routines that handle >1 char between left and right limits. fill_mode_table: .addr fillmode_copy,fillmode_or,fillmode2_xor,fillmode_bic .addr fillmode_copy,fillmode_or,fillmode2_xor,fillmode_bic ; Fill routines that handle only 1 char. fill_mode_table_onechar: .addr fillmode_copy_onechar,fillmode_or_onechar,fillmode2_xor_onechar,fillmode_bic_onechar .addr fillmode_copy_onechar,fillmode_or_onechar,fillmode2_xor_onechar,fillmode_bic_onechar ;;; ============================================================ ;;; SetPenMode .proc SetPenModeImpl lda current_penmode ldx #0 cmp #4 bcc :+ ldx #$7F : stx fill_eor_mask rts .endproc ;; Called from PaintRect, DrawText, etc to configure ;; fill routines from mode. .proc set_up_fill_mode x1 := $92 x2 := $96 x1_bytes := $86 x2_bytes := $82 add16 x_offset, x2, x2 add16 y_offset, bottom, bottom add16 x_offset, x1, x1 add16 y_offset, top, top lsr x2+1 beq :+ jmp rl_ge256 : lda x2 ror a tax lda div7_table,x ldy mod7_table,x set_x2_bytes: sta x2_bytes tya rol a tay lda aux_right_masks,y sta right_masks_table+1 lda main_right_masks,y sta right_masks_table lsr x1+1 bne ll_ge256 lda x1 ror a tax lda div7_table,x ldy mod7_table,x set_x1_bytes: sta x1_bytes tya rol a tay sty left_mod14 lda aux_left_masks,y sta left_masks_table+1 lda main_left_masks,y sta left_masks_table lda x2_bytes sec sbc x1_bytes set_width: ; Set width for destination. sta width_bytes pha lda current_penmode asl a tax pla bne :+ ; Check if one or more than one is needed lda left_masks_table+1 ; Only one char is needed, so combine and right_masks_table+1 ; the left and right masks and use the sta left_masks_table+1 ; one-char fill subroutine. sta right_masks_table+1 lda left_masks_table and right_masks_table sta left_masks_table sta right_masks_table copy16 fill_mode_table_onechar,x, fillmode_jmp+1 rts : copy16 fill_mode_table,x, fillmode_jmp+1 rts ll_ge256: ; Divmod for left limit >= 256 lda x1 ror a tax php lda div7_table+4,x clc adc #$24 plp ldy mod7_table+4,x bpl set_x1_bytes rl_ge256: ; Divmod for right limit >= 256 lda x2 ror a tax php lda div7_table+4,x clc adc #$24 plp ldy mod7_table+4,x bmi divmod7 jmp set_x2_bytes .endproc .proc divmod7 lsr a bne :+ txa ror a tax lda div7_table,x ldy mod7_table,x rts : txa ror a tax php lda div7_table+4,x clc adc #$24 plp ldy mod7_table+4,x rts .endproc ;; Set up destination (for either on-screen or off-screen bitmap.) .proc set_dest DEST_NDBM := 0 ; draw to off-screen bitmap DEST_DHGR := 1 ; draw to DHGR screen lda left_bytes ldx top ldy current_mapwidth jsr ndbm_calc_dest clc adc current_mapbits sta vid_addr tya adc current_mapbits+1 sta vid_addr+1 lda #2*DEST_DHGR tax tay bit current_mapwidth bmi on_screen ; negative for on-screen destination copy16 #bitmap_buffer, bits_addr jsr ndbm_fix_width txa inx stx src_width_bytes jsr set_up_fill_mode::set_width copy16 shift_line_jmp_addr, dhgr_get_srcbits::shift_bits_jmp_addr lda #2*DEST_NDBM ldx #2*DEST_NDBM ldy #2*DEST_NDBM on_screen: pha lda next_line_table,x sta dhgr_start_fill::next_line_jmp_addr lda next_line_table+1,x sta dhgr_start_fill::next_line_jmp_addr+1 pla tax copy16 start_fill_table,x, start_fill_jmp+1 copy16 shift_line_table,y, dhgr_shift_bits::shift_line_jmp_addr rts .endproc ;; Fix up the width and masks for an off-screen destination, ndbm_fix_width: lda width_bytes asl a tax inx lda left_masks_table+1 bne :+ dex inc bits_addr inc16 vid_addr lda left_masks_table : sta left_sidemask lda right_masks_table bne :+ dex lda right_masks_table+1 : sta right_sidemask rts ;; DEST_NDBM DEST_DHGR shift_line_jmp_addr: .addr shift_line_jmp start_fill_table: .addr ndbm_start_fill, dhgr_start_fill next_line_table: .addr ndbm_next_line, dhgr_next_line shift_line_table: .addr ndbm_next_line, dhgr_shift_line ;; Set source for bitmap transfer (either on-screen or off-screen bitmap.) .proc set_source SRC_NDBM := 0 SRC_DHGR := 1 ldx src_y_coord ldy src_mapwidth bmi :+ jsr mult_x_y : clc adc bits_addr sta ndbm_get_srcbits::load_addr tya adc bits_addr+1 sta ndbm_get_srcbits::load_addr+1 ldx #2*SRC_DHGR bit src_mapwidth bmi :+ ldx #2*SRC_NDBM : copy16 get_srcbits_table,x, fill_next_line::get_srcbits_jmp_addr rts ;; SRC_NDBM SRC_DHGR get_srcbits_table: .addr ndbm_get_srcbits, dhgr_get_srcbits .endproc ;; Calculate destination for off-screen bitmap. .proc ndbm_calc_dest bmi on_screen ; do nothing for on-screen destination asl a mult_x_y: stx $82 sty $83 ldx #8 loop: lsr $83 bcc :+ clc adc $82 : ror a ror vid_addr dex bne loop sty $82 tay lda vid_addr sec sbc $82 bcs on_screen dey on_screen: rts .endproc mult_x_y := ndbm_calc_dest::mult_x_y ;;; ============================================================ ;;; SetPattern ;; Expands the pattern to 8 rows of DHGR-style bitmaps at ;; $0400, $0440, $0480, $04C0, $0500, $0540, $0580, $05C0 ;; (using both main and aux mem.) .proc SetPatternImpl lda #pattern_buffer sta bits_addr+1 ldx #7 loop: lda x_offset and #7 tay lda current_penpattern,x : dey bmi :+ cmp #$80 rol a bne :- : ldy #$27 : pha lsr a sta LOWSCR sta (bits_addr),y pla ror a pha lsr a sta HISCR sta (bits_addr),y pla ror a dey bpl :- lda bits_addr sec sbc #$40 sta bits_addr bcs next ldy bits_addr+1 dey cpy #>pattern_buffer bcs :+ ldy #>pattern_buffer+1 : sty bits_addr+1 next: dex bpl loop sta LOWSCR rts .endproc ;;; ============================================================ ;;; FrameRect ;;; 8 bytes of params, copied to $9F frect_ctr: .byte 0 .proc FrameRectImpl left := $9F top := $A1 right := $A3 bottom := $A5 ldy #3 rloop: COPY_BYTES 8, left, left_masks_table ldx rect_sides,y lda left,x pha lda $A0,x ldx rect_coords,y sta $93,x pla sta left_masks_table,x sty frect_ctr jsr draw_line ldy frect_ctr dey bpl rloop COPY_BYTES 4, left, current_penloc .endproc prts: rts rect_sides: .byte 0,2,4,6 rect_coords: .byte 4,6,0,2 .proc draw_line x2 := right lda current_penwidth ; Also: draw horizontal line $92 to $96 at $98 sec sbc #1 cmp #$FF beq prts adc x2 sta x2 bcc :+ inc x2+1 : lda current_penheight sec sbc #1 cmp #$FF beq prts adc bottom sta bottom bcc PaintRectImpl inc bottom+1 ;; Fall through... .endproc ;;; ============================================================ ;;; PaintRect ;;; 8 bytes of params, copied to $92 .proc PaintRectImpl jsr check_rect do_paint: jsr clip_rect bcc prts jsr set_up_fill_mode jsr set_dest jmp do_fill .endproc ;;; ============================================================ ;;; InRect ;;; 8 bytes of params, copied to $92 .proc InRectImpl jsr check_rect ldax current_penloc_x cpx left+1 bmi fail bne :+ cmp left bcc fail : cpx right+1 bmi :+ bne fail cmp right bcc :+ bne fail : ldax current_penloc_y cpx top+1 bmi fail bne :+ cmp top bcc fail : cpx bottom+1 bmi :+ bne fail cmp bottom bcc :+ bne fail : exit_call MGTK::inrect_inside ; success! fail: rts .endproc ;;; ============================================================ ;;; SetPortBits .proc SetPortBitsImpl sub16 current_viewloc_x, current_maprect_x1, x_offset sub16 current_viewloc_y, current_maprect_y1, y_offset rts .endproc clipped_left := $9B ; number of bits clipped off left side clipped_top := $9D ; number of bits clipped off top side .proc clip_rect lda current_maprect_x2+1 cmp left+1 bmi fail bne in_left lda current_maprect_x2 cmp left bcs in_left fail: clc fail2: rts in_left: lda right+1 cmp current_maprect_x1+1 bmi fail bne in_right lda right cmp current_maprect_x1 bcc fail2 in_right: lda current_maprect_y2+1 cmp top+1 bmi fail bne in_bottom lda current_maprect_y2 cmp top bcc fail2 in_bottom: lda bottom+1 cmp current_maprect_y1+1 bmi fail bne in_top lda bottom cmp current_maprect_y1 bcc fail2 in_top: ldy #0 lda left sec sbc current_maprect_x1 tax lda left+1 sbc current_maprect_x1+1 bpl :+ stx clipped_left sta clipped_left+1 copy16 current_maprect_x1, left iny : lda current_maprect_x2 sec sbc right tax lda current_maprect_x2+1 sbc right+1 bpl :+ copy16 current_maprect_x2, right tya ora #$04 tay : lda top sec sbc current_maprect_y1 tax lda top+1 sbc current_maprect_y1+1 bpl :+ stx clipped_top sta clipped_top+1 copy16 current_maprect_y1, top iny iny : lda current_maprect_y2 sec sbc bottom tax lda current_maprect_y2+1 sbc bottom+1 bpl :+ copy16 current_maprect_y2, bottom tya ora #$08 tay : sty $9A sec rts .endproc .proc check_rect sec lda right sbc left lda right+1 sbc left+1 bmi bad_rect sec lda bottom sbc top lda bottom+1 sbc top+1 bmi bad_rect rts bad_rect: exit_call MGTK::Error::empty_object .endproc ;;; ============================================================ ;;; 16 bytes of params, copied to $8A src_width_bytes: .res 1 ; width of source data in chars unused_width: .res 1 ; holds the width of data, but is not used ??? .proc PaintBitsImpl dbi_left := $8A dbi_top := $8C dbi_bitmap := $8E ; aka bits_addr dbi_stride := $90 ; aka src_mapwidth dbi_hoff := $92 ; aka left dbi_voff := $94 ; aka top dbi_width := $96 ; aka right dbi_height := $98 ; aka bottom dbi_x := $9B dbi_y := $9D offset := $82 ldx #3 ; copy left/top to $9B/$9D : lda dbi_left,x ; and hoff/voff to $8A/$8C (overwriting left/top) sta dbi_x,x lda dbi_hoff,x sta dbi_left,x dex bpl :- sub16 dbi_width, dbi_hoff, offset lda dbi_x sta left clc adc offset sta right lda dbi_x+1 sta left+1 adc offset+1 sta right+1 sub16 dbi_height, dbi_voff, offset lda dbi_y sta top clc adc offset sta bottom lda dbi_y+1 sta top+1 adc offset+1 sta bottom+1 ;; fall through to BitBlt .endproc ;;; ============================================================ ;;; $4D BitBlt ;;; 16 bytes of params, copied to $8A src_byte_off := $8A ; char offset within source line bit_offset := $9B shift_bytes := $81 .proc BitBltImpl lda #0 sta clipped_left sta clipped_left+1 sta clipped_top lda bits_addr+1 sta $80 jsr clip_rect bcs :+ rts : jsr set_up_fill_mode lda width_bytes asl a ldx left_masks_table+1 ; need left mask on aux? beq :+ adc #1 : ldx right_masks_table ; need right mask on main? beq :+ adc #1 : sta unused_width sta src_width_bytes ; adjusted width in chars lda #2 sta shift_bytes lda #0 ; Calculate starting Y-coordinate sec ; = dbi_top - clipped_top sbc clipped_top clc adc PaintBitsImpl::dbi_top sta PaintBitsImpl::dbi_top lda #0 ; Calculate starting X-coordinate sec ; = dbi_left - clipped_left sbc clipped_left tax lda #0 sbc clipped_left+1 tay txa clc adc PaintBitsImpl::dbi_left tax tya adc PaintBitsImpl::dbi_left+1 jsr divmod7 sta src_byte_off tya ; bit offset between src and dest rol a cmp #7 ldx #1 bcc :+ dex sbc #7 : stx dhgr_get_srcbits::offset1_addr inx stx dhgr_get_srcbits::offset2_addr sta bit_offset lda src_byte_off rol a jsr set_source jsr set_dest copy16 #bitmap_buffer, bits_addr ldx #1 lda left_mod14 sec sbc #7 bcc :+ sta left_mod14 dex : stx dhgr_shift_line::offset1_addr inx stx dhgr_shift_line::offset2_addr lda left_mod14 sec sbc bit_offset bcs :+ adc #7 inc src_width_bytes dec shift_bytes : tay ; check if bit shift required bne :+ ldx #2*BITS_NO_BITSHIFT beq no_bitshift : tya asl a tay copy16 shift_table_main,y, dhgr_shift_bits::shift_main_addr copy16 shift_table_aux,y, dhgr_shift_bits::shift_aux_addr ldy shift_bytes sty dhgr_shift_bits::offset2_addr dey sty dhgr_shift_bits::offset1_addr ldx #2*BITS_BITSHIFT no_bitshift: copy16 shift_bits_table,x, dhgr_get_srcbits::shift_bits_jmp_addr jmp bit_blit BITS_NO_BITSHIFT := 0 BITS_BITSHIFT := 1 ;; BITS_NO_BITSHIFT BITS_BITSHIFT shift_bits_table: .addr shift_line_jmp, dhgr_shift_bits .endproc shift_table_aux := *-2 .addr shift_1_aux,shift_2_aux,shift_3_aux .addr shift_4_aux,shift_5_aux,shift_6_aux shift_table_main := *-2 .addr shift_1_main,shift_2_main,shift_3_main .addr shift_4_main,shift_5_main,shift_6_main vertex_limit := $B3 vertices_count := $B4 poly_oper := $BA ; positive = paint; negative = test start_index := $AE poly_oper_paint := $00 poly_oper_test := $80 .proc load_poly point_index := $82 low_point := $A7 max_poly_points := 60 stx $B0 asl a asl a ; # of vertices * 4 = length sta vertex_limit ;; Initialize rect to first point of polygon. ldy #3 ; Copy params_addr... to $92... and $96... : lda (params_addr),y sta left,y sta right,y dey bpl :- copy16 top, low_point ; y coord ldy #0 stx start_index loop: stx point_index lda (params_addr),y sta poly_xl_buffer,x pha iny lda (params_addr),y sta poly_xh_buffer,x tax pla iny cpx left+1 bmi :+ bne in_left cmp left bcs in_left : stax left bcc in_right in_left: cpx right+1 bmi in_right bne :+ cmp right bcc in_right : stax right in_right: ldx point_index lda (params_addr),y sta poly_yl_buffer,x pha iny lda (params_addr),y sta poly_yh_buffer,x tax pla iny cpx top+1 bmi :+ bne in_top cmp top bcs in_top : stax top bcc in_bottom in_top: cpx bottom+1 bmi in_bottom bne :+ cmp bottom bcc in_bottom : stax bottom in_bottom: cpx low_point+1 stx low_point+1 bmi set_low_point bne :+ cmp low_point bcc set_low_point beq set_low_point : ldx point_index stx start_index set_low_point: sta low_point ldx point_index inx cpx #max_poly_points beq bad_poly cpy vertex_limit bcc loop lda top cmp bottom bne :+ lda top+1 cmp bottom+1 beq bad_poly : stx vertex_limit bit poly_oper bpl :+ sec rts : jmp clip_rect .endproc .proc next_poly lda vertices_count bpl orts asl a asl a adc params_addr sta params_addr bcc ora_2_param_bytes inc params_addr+1 ;; Fall-through .endproc ;; ORAs together first two bytes at (params_addr) and stores ;; in $B4, then advances params_addr ora_2_param_bytes: ldy #0 lda (params_addr),y iny ora (params_addr),y sta vertices_count inc16 params_addr inc16 params_addr ldy #$80 orts: rts ;;; ============================================================ ;;; InPoly InPolyImpl: lda #poly_oper_test bne PaintPolyImpl_entry2 ;;; ============================================================ ;;; PaintPoly ;; also called from the end of LineToImpl num_maxima := $AD max_num_maxima := 8 low_vertex := $B0 .proc PaintPolyImpl lda #poly_oper_paint entry2: sta poly_oper ldx #0 stx num_maxima jsr ora_2_param_bytes loop: jsr load_poly bcs process_poly ldx low_vertex next: jsr next_poly bmi loop jmp fill_polys bad_poly: exit_call MGTK::Error::bad_object .endproc temp_yh := $83 next_vertex := $AA current_vertex := $AC loop_ctr := $AF .proc process_poly ldy #1 sty loop_ctr ; do 2 iterations of the following loop ldy start_index ; starting vertex cpy low_vertex ; lowest vertex bne :+ ldy vertex_limit ; highest vertex : dey sty $AB ; one before starting vertex php loop: sty current_vertex ; current vertex iny cpy vertex_limit bne :+ ldy low_vertex : sty next_vertex ; next vertex cpy start_index ; have we come around complete circle? bne :+ dec loop_ctr ; this completes one loop : lda poly_yl_buffer,y ldx poly_yh_buffer,y stx temp_yh vloop: sty $A9 ; starting from next vertex, search ahead iny ; for a subsequent vertex with differing y cpy vertex_limit bne :+ ldy low_vertex : cmp poly_yl_buffer,y bne :+ ldx poly_yh_buffer,y cpx temp_yh beq vloop : ldx $AB ; find y difference with current vertex sec sbc poly_yl_buffer,x lda temp_yh sbc poly_yh_buffer,x bmi y_less lda $A9 ; vertex before new vertex plp ; check maxima flag bmi new_maxima ; if set, go create new maxima tay sta poly_vertex_prev_link,x ; link current vertex -> vertex before new vertex lda next_vertex sta poly_vertex_next_link,x ; link current vertex -> next vertex bpl next new_maxima: ldx num_maxima cpx #2*max_num_maxima ; too many maxima points (documented limitation) bcs bad_poly sta poly_maxima_prev_vertex,x ; vertex before new vertex lda next_vertex sta poly_maxima_next_vertex,x ; current vertex ldy $AB lda poly_vertex_prev_link,y sta poly_maxima_prev_vertex+1,x lda poly_vertex_next_link,y sta poly_maxima_next_vertex+1,x lda poly_yl_buffer,y sta poly_maxima_yl_table,x sta poly_maxima_yl_table+1,x lda poly_yh_buffer,y sta poly_maxima_yh_table,x sta poly_maxima_yh_table+1,x lda poly_xl_buffer,y sta poly_maxima_xl_table+1,x lda poly_xh_buffer,y sta poly_maxima_xh_table+1,x ldy current_vertex lda poly_xl_buffer,y sta poly_maxima_xl_table,x lda poly_xh_buffer,y sta poly_maxima_xh_table,x inx inx stx num_maxima ldy $A9 bpl next y_less: plp ; check maxima flag bmi :+ lda #$80 sta poly_vertex_prev_link,x ; link current vertex -> #$80 : ldy next_vertex txa sta poly_vertex_prev_link,y ; link next vertex -> current vertex lda current_vertex sta poly_vertex_next_link,y lda #$80 ; set negative flag so next iteration captures a maxima next: php sty $AB ldy $A9 bit loop_ctr bmi :+ jmp loop : plp ldx vertex_limit jmp PaintPolyImpl::next .endproc scan_y := $A9 lr_flag := $AB start_maxima := $B1 .proc fill_polys ldx #0 stx start_maxima lda #$80 sta poly_maxima_links sta $B2 loop: inx cpx num_maxima bcc :+ beq links_done rts : lda start_maxima next_link: tay lda poly_maxima_yl_table,x cmp poly_maxima_yl_table,y bcs x_ge_y tya ; poly_maxima_y[xReg] < poly_maxima_y[yReg] sta poly_maxima_links,x ; then xReg linked to yReg cpy start_maxima beq :+ ; if yReg was the start, set the start to xReg ldy $82 txa sta poly_maxima_links,y ; else $82 linked to xReg jmp loop : stx start_maxima ; set start to xReg bcs loop ; always x_ge_y: sty $82 ; poly_maxima_y[xReg] >= poly_maxima_y[yReg] lda poly_maxima_links,y bpl next_link ; if yReg was the end sta poly_maxima_links,x ; then set xReg as end txa sta poly_maxima_links,y ; and link yReg to xReg bpl loop ; always links_done: ldx start_maxima lda poly_maxima_yl_table,x sta scan_y sta top lda poly_maxima_yh_table,x sta scan_y+1 sta top+1 scan_loop: ldx start_maxima bmi L5534 scan_next: lda poly_maxima_yl_table,x cmp scan_y bne L5532 lda poly_maxima_yh_table,x cmp scan_y+1 bne L5532 lda poly_maxima_links,x sta $82 jsr calc_slope lda $B2 bmi L5517 L54E0: tay lda poly_maxima_xh_table,x cmp poly_maxima_xh_table,y bmi L5520 bne :+ lda poly_maxima_xl_table,x cmp poly_maxima_xl_table,y bcc L5520 bne :+ lda poly_maxima_x_frach,x cmp poly_maxima_x_frach,y bcc L5520 bne :+ lda poly_maxima_x_fracl,x cmp poly_maxima_x_fracl,y bcc L5520 : sty $83 lda poly_maxima_links,y bpl L54E0 sta poly_maxima_links,x txa sta poly_maxima_links,y bpl L552E L5517: sta poly_maxima_links,x stx $B2 jmp L552E done: rts L5520: tya cpy $B2 beq L5517 sta poly_maxima_links,x txa ldy $83 sta poly_maxima_links,y L552E: ldx $82 bpl scan_next L5532: stx $B1 L5534: lda #0 sta lr_flag lda $B2 sta $83 bmi done scan_loop2: tax lda scan_y cmp poly_maxima_yl_table,x bne scan_point lda scan_y+1 cmp poly_maxima_yh_table,x bne scan_point ldy poly_maxima_prev_vertex,x lda poly_vertex_prev_link,y bpl shift_point cpx $B2 beq :+ ldy $83 lda poly_maxima_links,x sta poly_maxima_links,y jmp scan_next_link : lda poly_maxima_links,x sta $B2 jmp scan_next_link shift_point: sta poly_maxima_prev_vertex,x lda poly_xl_buffer,y sta poly_maxima_xl_table,x lda poly_xh_buffer,y sta poly_maxima_xh_table,x lda poly_vertex_next_link,y sta poly_maxima_next_vertex,x jsr calc_slope scan_point: stx current_vertex ldy poly_maxima_xh_table,x lda poly_maxima_xl_table,x tax lda lr_flag ; alternate flag left/right eor #$FF sta lr_flag bpl :+ stx left sty left+1 bmi skip_rect : stx right sty right+1 cpy left+1 bmi :+ bne no_swap_lr cpx left bcs no_swap_lr : lda left stx left sta right lda left+1 sty left+1 sta right+1 no_swap_lr: lda scan_y sta top sta bottom lda scan_y+1 sta top+1 sta bottom+1 bit poly_oper bpl do_paint jsr InRectImpl jmp skip_rect do_paint: jsr PaintRectImpl::do_paint skip_rect: ldx current_vertex lda poly_maxima_x_fracl,x clc adc poly_maxima_slope0,x sta poly_maxima_x_fracl,x lda poly_maxima_x_frach,x adc poly_maxima_slope1,x sta poly_maxima_x_frach,x lda poly_maxima_xl_table,x adc poly_maxima_slope2,x sta poly_maxima_xl_table,x lda poly_maxima_xh_table,x adc poly_maxima_slope3,x sta poly_maxima_xh_table,x lda poly_maxima_links,x scan_next_link: bmi :+ jmp scan_loop2 : inc16 scan_y jmp scan_loop .endproc .proc calc_slope index := $84 ldy poly_maxima_next_vertex,x lda poly_yl_buffer,y sta poly_maxima_yl_table,x sec sbc scan_y sta = 17, skip this next bit bcs end ldax current_textfont clc adc #3 bcc :+ inx : stax glyph_widths ; set $FB/$FC to start of widths sec adc glyph_last bcc :+ inx : ldy #0 ; loop 0... height-1 loop: sta glyph_row_lo,y pha txa sta glyph_row_hi,y pla sec adc glyph_last bcc :+ inx : bit glyph_type ; ($80 = double width, so double the offset) bpl :+ sec adc glyph_last bcc :+ inx : iny cpy glyph_height_p bne loop rts end: exit_call MGTK::Error::font_too_big .endproc glyph_row_lo: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 glyph_row_hi: .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 ;;; ============================================================ ;;; TextWidth ;;; 3 bytes of params, copied to $A1 .proc TextWidthImpl jsr measure_text ldy #3 ; Store result (X,A) at params+3 sta (params_addr),y txa iny sta (params_addr),y rts .endproc ;; Call with data at ($A1), length in $A3, result in (X,A) .proc measure_text data := $A1 length := $A3 accum := $82 ldx #0 ldy #0 sty accum loop: sty accum+1 lda (data),y tay txa clc adc (glyph_widths),y bcc :+ inc accum : tax ldy accum+1 iny cpy length bne loop txa ldx accum rts .endproc ;;; ============================================================ ;; Turn the current penloc into left, right, top, and bottom. ;; ;; Inputs: ;; A = width ;; $FF = height ;; .proc penloc_to_bounds sec sbc #1 bcs :+ dex : clc adc current_penloc_x sta right txa adc current_penloc_x+1 sta right+1 copy16 current_penloc_x, left lda current_penloc_y sta bottom ldx current_penloc_y+1 stx bottom+1 clc adc #1 bcc :+ inx : sec sbc glyph_height_p bcs :+ dex : stax top rts .endproc ;;; ============================================================ ;;; 3 bytes of params, copied to $A1 .proc DrawTextImpl text_bits_buf := $00 vid_addrs_table := $20 shift_aux_ptr := $40 shift_main_ptr := $42 blit_mask := $80 doublewidth_flag := $81 remaining_width := $9A vid_page := $9C text_index := $9F text_addr := $A1 ; param text_len := $A3 ; param text_width := $A4 ; computed jsr maybe_unstash_low_zp jsr measure_text stax text_width ldy #0 sty text_index sty $A0 sty clipped_left sty clipped_top jsr penloc_to_bounds jsr clip_rect bcc text_clipped tya ror a bcc no_left_clip ldy #0 ldx vid_page left_clip_loop: sty text_index lda (text_addr),y tay lda (glyph_widths),y clc adc clipped_left ; exit loop when first partially or bcc :+ ; fully visible glyph is found inx beq no_left_clip : sta clipped_left ldy text_index iny bne left_clip_loop no_left_clip: jsr set_up_fill_mode jsr set_dest lda left_mod14 clc adc clipped_left bpl :+ inc width_bytes dec $A0 adc #14 : sta left_mod14 lda width_bytes inc width_bytes ldy current_mapwidth bpl text_clip_ndbm ;; For an on-screen destination, width_bytes is set up for the ;; pattern blitter, which thinks in terms of double (main & aux) ;; transfers. We actually want single transfers here, so we need to ;; double it and restore the carry. asl a tax lda left_mod14 cmp #7 bcs :+ inx : lda right beq :+ inx : stx width_bytes text_clip_ndbm: lda left_mod14 sec sbc #7 bcc :+ sta left_mod14 : lda #0 rol a ; if left_mod14 was >= 7, then A=1 else A=0 eor #1 ; if left_mod14 <7, then A=1 (aux) else A=0 (main) sta vid_page tax sta LOWSCR,x ; set starting page jsr do_draw sta LOWSCR text_clipped: jsr maybe_stash_low_zp ldax text_width jmp adjust_xpos do_draw: lda bottom sec sbc top asl a tax ;; Calculate offsets to the draw and blit routines so that they draw ;; the exact number of needed lines. lda shifted_draw_line_table,x sta shifted_draw_jmp_addr lda shifted_draw_line_table+1,x sta shifted_draw_jmp_addr+1 lda unshifted_draw_line_table,x sta unshifted_draw_jmp_addr lda unshifted_draw_line_table+1,x sta unshifted_draw_jmp_addr+1 lda unmasked_blit_line_table,x sta unmasked_blit_jmp_addr lda unmasked_blit_line_table+1,x sta unmasked_blit_jmp_addr+1 lda masked_blit_line_table,x sta masked_blit_jmp_addr lda masked_blit_line_table+1,x sta masked_blit_jmp_addr+1 txa lsr a tax sec stx $80 stx $81 lda #0 sbc clipped_top sta clipped_top tay ldx #(max_font_height-1)*shifted_draw_line_size sec : lda glyph_row_lo,y sta shifted_draw_linemax+1,x lda glyph_row_hi,y sta shifted_draw_linemax+2,x txa sbc #shifted_draw_line_size tax iny dec $80 bpl :- ldy clipped_top ldx #(max_font_height-1)*unshifted_draw_line_size sec : lda glyph_row_lo,y sta unshifted_draw_linemax+1,x lda glyph_row_hi,y sta unshifted_draw_linemax+2,x txa sbc #unshifted_draw_line_size tax iny dec $81 bpl :- ldy top ldx #0 ;; Populate the pointers in vid_addrs_table for the lines we are ;; going to be drawing to. text_dest_loop: bit current_mapwidth bmi text_dest_dhgr lda vid_addr clc adc current_mapwidth sta vid_addr sta vid_addrs_table,x lda vid_addr+1 adc #0 sta vid_addr+1 sta vid_addrs_table+1,x bne text_dest_next text_dest_dhgr: lda hires_table_lo,y clc adc left_bytes sta vid_addrs_table,x lda hires_table_hi,y ora current_mapbits+1 sta vid_addrs_table+1,x text_dest_next: cpy bottom beq :+ iny inx inx bne text_dest_loop : ldx #15 lda #0 : sta text_bits_buf,x dex bpl :- sta doublewidth_flag sta shift_aux_ptr ; zero lda #$80 sta shift_main_ptr ldy text_index next_glyph: lda (text_addr),y tay bit doublewidth_flag bpl :+ sec adc glyph_last : tax lda (glyph_widths),y beq zero_width_glyph ldy left_mod14 bne shifted_draw ;; Transfer one column of one glyph into the text_bits_buf[0..15] unshifted_draw_jmp_addr := *+1 jmp unshifted_draw_linemax ; patched to jump into following block ;; Unrolled loop from max_font_height-1 down to 0 unshifted_draw_linemax: .repeat max_font_height, line .ident (.sprintf ("unshifted_draw_line_%d", max_font_height-line-1)): : lda $FFFF,x sta text_bits_buf+max_font_height-line-1 .ifndef unshifted_draw_line_size unshifted_draw_line_size := * - :- .else .assert unshifted_draw_line_size = * - :-, error, "unshifted_draw_line_size inconsistent" .endif .endrepeat zero_width_glyph: jmp do_blit ;; Transfer one column of one glyph, shifting it into ;; text_bits_buf[0..15] and text_bits_buf[16..31] by left_mod14 bits. shifted_draw: tya asl a tay copy16 shift_table_aux,y, shift_aux_ptr copy16 shift_table_main,y, shift_main_ptr shifted_draw_jmp_addr := *+1 jmp shifted_draw_linemax ; patched to jump into following block ;; Unrolled loop from max_font_height-1 down to 0 shifted_draw_linemax: .repeat max_font_height, line .ident (.sprintf ("shifted_draw_line_%d", max_font_height-line-1)): : ldy $FFFF,x ; All of these $FFFFs are modified lda (shift_main_ptr),y sta text_bits_buf+16+max_font_height-line-1 lda (shift_aux_ptr),y ora text_bits_buf+max_font_height-line-1 sta text_bits_buf+max_font_height-line-1 .ifndef shifted_draw_line_size shifted_draw_line_size := * - :- .else .assert shifted_draw_line_size = * - :-, error, "shifted_draw_line_size inconsistent" .endif .endrepeat do_blit: bit doublewidth_flag bpl :+ inc text_index ; completed a double-width glyph lda #0 sta doublewidth_flag lda remaining_width bne advance_x ; always : txa tay lda (glyph_widths),y cmp #8 bcs :+ inc text_index ; completed a single-width glyph bcc advance_x : sbc #7 sta remaining_width ror doublewidth_flag ; will set to negative lda #7 ; did the first 7 pixels of a ; double-width glyph advance_x: clc adc left_mod14 cmp #7 bcs advance_byte sta left_mod14 L5BFF: ldy text_index cpy text_len beq :+ jmp next_glyph : ldy $A0 jmp last_blit advance_byte: sbc #7 sta left_mod14 ldy $A0 bne :+ jmp first_blit : bmi next_byte dec width_bytes bne unmasked_blit jmp last_blit unmasked_blit: unmasked_blit_jmp_addr := *+1 jmp unmasked_blit_linemax ; patched to jump into block below ;;; Per JB: "looks like the quickdraw fast-path draw unclipped pattern slab" ;; Unrolled loop from max_font_height-1 down to 0 unmasked_blit_linemax: .repeat max_font_height, line .ident (.sprintf ("unmasked_blit_line_%d", max_font_height-line-1)): : lda text_bits_buf+max_font_height-line-1 eor current_textback sta (vid_addrs_table + 2*(max_font_height-line-1)),y .ifndef unmasked_blit_line_size unmasked_blit_line_size := * - :- .else .assert unmasked_blit_line_size = * - :-, error, "unmasked_blit_line_size inconsistent" .endif .endrepeat next_byte: bit current_mapwidth bpl text_ndbm lda vid_page eor #1 tax sta vid_page sta LOWSCR,x beq :+ text_ndbm: inc $A0 : COPY_BYTES 16, text_bits_buf+16, text_bits_buf jmp L5BFF ;; This is the first (left-most) blit, so it needs masks. If this is ;; also the last blit, apply the right mask as well. first_blit: ldx vid_page lda left_masks_table,x dec width_bytes beq single_byte_blit jsr masked_blit jmp next_byte single_byte_blit: ; a single byte length blit; i.e. start and right_masks_table,x ; and end bytes are the same bne masked_blit rts ;; This is the last (right-most) blit, so we have to set up masking. last_blit: ldx vid_page lda right_masks_table,x masked_blit: ora #$80 sta blit_mask masked_blit_jmp_addr := *+1 jmp masked_blit_linemax ;;; Per JB: "looks like the quickdraw slow-path draw clipped pattern slab" ;; Unrolled loop from max_font_height-1 down to 0 masked_blit_linemax: .repeat max_font_height, line .ident (.sprintf ("masked_blit_line_%d", max_font_height-line-1)): : lda text_bits_buf+max_font_height-line-1 eor current_textback eor (vid_addrs_table + 2*(max_font_height-line-1)),y and blit_mask eor (vid_addrs_table + 2*(max_font_height-line-1)),y sta (vid_addrs_table + 2*(max_font_height-line-1)),y .ifndef masked_blit_line_size masked_blit_line_size := * - :- .else .assert masked_blit_line_size = * - :-, error, "masked_blit_line_size inconsistent" .endif .endrepeat rts shifted_draw_line_table: .repeat max_font_height, line .addr .ident (.sprintf ("shifted_draw_line_%d", line)) .endrepeat unshifted_draw_line_table: .repeat max_font_height, line .addr .ident (.sprintf ("unshifted_draw_line_%d", line)) .endrepeat unmasked_blit_line_table: .repeat max_font_height, line .addr .ident (.sprintf ("unmasked_blit_line_%d", line)) .endrepeat masked_blit_line_table: .repeat max_font_height, line .addr .ident (.sprintf ("masked_blit_line_%d", line)) .endrepeat .endproc ;;; ============================================================ low_zp_stash_buffer: poly_maxima_yh_table: .res 16 poly_maxima_x_frach: .res 16 poly_maxima_x_fracl: .res 16 poly_maxima_xl_table: .res 16 poly_maxima_xh_table: .res 16 ;;; ============================================================ ;;; InitGraf .proc InitGrafImpl lda #$71 ; %0001 lo nibble = HiRes, Page 1, Full, Graphics sta $82 ; (why is high nibble 7 ???) jsr SetSwitchesImpl ;; Initialize port ldx #.sizeof(MGTK::GrafPort)-1 loop: lda standard_port,x sta $8A,x sta current_grafport,x dex bpl loop ldax saved_port_addr jsr assign_and_prepare_port lda #$7F sta fill_eor_mask jsr PaintRectImpl lda #$00 sta fill_eor_mask rts saved_port_addr: .addr saved_port .endproc ;;; ============================================================ ;;; SetSwitches ;;; 1 byte param, copied to $82 ;;; Toggle display softswitches ;;; bit 0: LoRes if clear, HiRes if set ;;; bit 1: Page 1 if clear, Page 2 if set ;;; bit 2: Full screen if clear, split screen if set ;;; bit 3: Graphics if clear, text if set .proc SetSwitchesImpl PARAM_BLOCK params, $82 switches: .res 1 END_PARAM_BLOCK lda DHIRESON ; enable dhr graphics sta SET80VID ldx #3 loop: lsr params::switches ; shift low bit into carry lda table,x rol a tay ; y = table[x] * 2 + carry bcs store lda $C000,y ; why load vs. store ??? bcc :+ store: sta $C000,y : dex bpl loop rts table: .byte <(TXTCLR / 2), <(MIXCLR / 2), <(LOWSCR / 2), <(LORES / 2) .endproc ;;; ============================================================ ;;; SetPort .proc SetPortImpl ldax params_addr ;; fall through .endproc ;; Call with port address in (X,A) assign_and_prepare_port: stax active_port ;; fall through ;; Initializes font (if needed), port, pattern, and fill mode prepare_port: lda current_textfont+1 beq :+ ; only prepare font if necessary jsr SetFontImpl::prepare_font : jsr SetPortBitsImpl jsr SetPatternImpl jmp SetPenModeImpl ;;; ============================================================ ;;; GetPort .proc GetPortImpl jsr apply_port_to_active_port ldax active_port ;; fall through .endproc ;; Store result (X,A) at params store_xa_at_params: ldy #0 ;; Store result (X,A) at params+Y store_xa_at_y: sta (params_addr),y txa iny sta (params_addr),y rts ;;; ============================================================ ;;; InitPort .proc InitPortImpl ldy #.sizeof(MGTK::GrafPort)-1 ; Store 36 bytes at params loop: lda standard_port,y sta (params_addr),y dey bpl loop .endproc rts3: rts ;;; ============================================================ ;;; SetZP1 ;;; 1 byte of params, copied to $82 .proc SetZP1Impl PARAM_BLOCK params, $82 flag: .res 1 END_PARAM_BLOCK lda params::flag cmp preserve_zp_flag beq rts3 sta preserve_zp_flag bcc rts3 jmp dispatch::cleanup .endproc ;;; ============================================================ ;;; SetZP2 ;;; 1 byte of params, copied to $82 ;;; If high bit set stash ZP $00-$43 to buffer if not already stashed. ;;; If high bit clear unstash ZP $00-$43 from buffer if not already unstashed. .proc SetZP2Impl PARAM_BLOCK params, $82 flag: .res 1 END_PARAM_BLOCK lda params::flag cmp low_zp_stash_flag beq rts3 sta low_zp_stash_flag bcc unstash maybe_stash: bit low_zp_stash_flag bpl end ;; Copy buffer to ZP $00-$43 stash: COPY_BYTES $44, low_zp_stash_buffer, $00 end: rts maybe_unstash: bit low_zp_stash_flag bpl end ;; Copy ZP $00-$43 to buffer unstash: COPY_BYTES $44, $00, low_zp_stash_buffer rts .endproc maybe_stash_low_zp := SetZP2Impl::maybe_stash maybe_unstash_low_zp := SetZP2Impl::maybe_unstash ;;; ============================================================ ;;; Version .proc VersionImpl ldy #5 ; Store 6 bytes at params loop: lda version,y sta (params_addr),y dey bpl loop rts .proc version major: .byte 1 ; 1.0.0 minor: .byte 0 patch: .byte 0 status: .byte 'F' ; Final??? release:.byte 1 ; ??? .byte 0 ; ??? .endproc .endproc ;;; ============================================================ preserve_zp_flag: ; if high bit set, ZP saved during MGTK calls .byte $80 low_zp_stash_flag: .byte $80 stack_ptr_stash: .byte 0 ;;; ============================================================ ;;; Standard GrafPort .proc standard_port viewloc: .word 0, 0 mapbits: .addr MGTK::screen_mapbits mapwidth: .word MGTK::screen_mapwidth maprect: .word 0, 0, screen_width-1, screen_height-1 penpattern: .res 8, $FF colormasks: .byte MGTK::colormask_and, MGTK::colormask_or penloc: .word 0, 0 penwidth: .byte 1 penheight: .byte 1 mode: .byte 0 textback: .byte 0 textfont: .addr 0 .endproc ;;; ============================================================ .proc saved_port viewloc: .word 0, 0 mapbits: .addr MGTK::screen_mapbits mapwidth: .word MGTK::screen_mapwidth maprect: .word 0, 0, screen_width-1, screen_height-1 penpattern: .res 8, $FF colormasks: .byte MGTK::colormask_and, MGTK::colormask_or penloc: .word 0, 0 penwidth: .byte 1 penheight: .byte 1 mode: .byte 0 textback: .byte 0 textfont: .addr 0 .endproc active_saved: ; saved copy of $F4...$FF when ZP swapped .addr saved_port .res 10, 0 zp_saved: ; top half of ZP for when preserve_zp_flag set .res 128, 0 ;; cursor shown/hidden flags/counts cursor_flag: ; high bit clear if cursor drawn, set if not drawn .byte 0 cursor_count: .byte $FF ; decremented on hide, incremented on shown; 0 = visible .proc set_pos_params xcoord: .word 0 ycoord: .word 0 .endproc mouse_state: mouse_x: .word 0 mouse_y: .word 0 mouse_status: .byte 0 ; bit 7 = is down, bit 6 = was down, still down mouse_scale_x: .byte $00 mouse_scale_y: .byte $00 mouse_hooked_flag: ; High bit set if mouse is "hooked", and calls .byte 0 ; bypassed; never appears to be set. mouse_hook: .addr 0 cursor_hotspot_x: .byte $00 cursor_hotspot_y: .byte $00 cursor_mod7: .res 1 cursor_bits: .res 3 cursor_mask: .res 3 cursor_savebits: .res 3*MGTK::cursor_height ; Saved 3 screen bytes per row. cursor_data: .res 4 ; Saved values of cursor_char..cursor_y2. pointer_cursor: .byte px(%0000000),px(%0000000) .byte px(%0100000),px(%0000000) .byte px(%0110000),px(%0000000) .byte px(%0111000),px(%0000000) .byte px(%0111100),px(%0000000) .byte px(%0111110),px(%0000000) .byte px(%0111111),px(%0000000) .byte px(%0101100),px(%0000000) .byte px(%0000110),px(%0000000) .byte px(%0000110),px(%0000000) .byte px(%0000011),px(%0000000) .byte px(%0000000),px(%0000000) .byte px(%1100000),px(%0000000) .byte px(%1110000),px(%0000000) .byte px(%1111000),px(%0000000) .byte px(%1111100),px(%0000000) .byte px(%1111110),px(%0000000) .byte px(%1111111),px(%0000000) .byte px(%1111111),px(%1000000) .byte px(%1111111),px(%0000000) .byte px(%0001111),px(%0000000) .byte px(%0001111),px(%0000000) .byte px(%0000111),px(%1000000) .byte px(%0000111),px(%1000000) .byte 1,1 pointer_cursor_addr: .addr pointer_cursor .proc set_pointer_cursor lda #$FF sta cursor_count lda #0 sta cursor_flag lda pointer_cursor_addr sta params_addr lda pointer_cursor_addr+1 sta params_addr+1 ;; fall through .endproc ;;; ============================================================ ;;; SetCursor .proc SetCursorImpl php sei ldax params_addr stax active_cursor clc adc #MGTK::Cursor::mask bcc :+ inx : stax active_cursor_mask ldy #MGTK::Cursor::hotspot lda (params_addr),y sta cursor_hotspot_x iny lda (params_addr),y sta cursor_hotspot_y jsr restore_cursor_background jsr draw_cursor plp .endproc srts: rts cursor_bytes := $82 cursor_softswitch := $83 cursor_y1 := $84 cursor_y2 := $85 vid_ptr := $88 .proc update_cursor lda cursor_count ; hidden? if so, skip bne srts bit cursor_flag bmi srts ;; Fall-through .endproc .proc draw_cursor lda #0 sta cursor_count sta cursor_flag lda set_pos_params::ycoord clc sbc cursor_hotspot_y sta cursor_y1 clc adc #MGTK::cursor_height sta cursor_y2 lda set_pos_params::xcoord sec sbc cursor_hotspot_x tax lda set_pos_params::xcoord+1 sbc #0 bpl :+ txa ; X-coord is negative: X-reg = X-coord + 256 ror a ; Will shift in zero: X-reg = X-coord/2 + 128 tax ; Negative mod7 table starts at 252 (since 252%7 = 0), and goes backwards ldy mod7_table+252-128,x ; Index (X-coord / 2 = X-reg - 128) relative to mod7_table+252 lda #$FF ; Char index = -1 bmi set_divmod : jsr divmod7 set_divmod: sta cursor_bytes ; char index in line tya rol a cmp #7 bcc :+ sbc #7 : tay lda #= 7, then will be HISCR, else LOWSCR eor #1 sta cursor_softswitch ; $C0xx softswitch index sty cursor_mod7 tya asl a tay copy16 shift_table_main,y, cursor_shift_main_addr copy16 shift_table_aux,y, cursor_shift_aux_addr ldx #3 : lda cursor_bytes,x sta cursor_data,x dex bpl :- ldx #$17 stx left_bytes ldx #$23 ldy cursor_y2 dloop: cpy #192 bcc :+ jmp drnext : lda hires_table_lo,y sta vid_ptr lda hires_table_hi,y ora #$20 sta vid_ptr+1 sty cursor_y2 stx left_mod14 ldy left_bytes ldx #$01 : active_cursor := * + 1 lda $FFFF,y sta cursor_bits,x active_cursor_mask := * + 1 lda $FFFF,y sta cursor_mask,x dey dex bpl :- lda #0 sta cursor_bits+2 sta cursor_mask+2 ldy cursor_mod7 beq no_shift ldy #5 : ldx cursor_bits-1,y cursor_shift_main_addr := * + 1 ora $FF80,x sta cursor_bits,y cursor_shift_aux_addr := * + 1 lda $FF00,x dey bne :- sta cursor_bits no_shift: ldx left_mod14 ldy cursor_bytes lda cursor_softswitch jsr set_switch bcs :+ lda (vid_ptr),y sta cursor_savebits,x lda cursor_mask ora (vid_ptr),y eor cursor_bits sta (vid_ptr),y dex : jsr switch_page bcs :+ lda (vid_ptr),y sta cursor_savebits,x lda cursor_mask+1 ora (vid_ptr),y eor cursor_bits+1 sta (vid_ptr),y dex : jsr switch_page bcs :+ lda (vid_ptr),y sta cursor_savebits,x lda cursor_mask+2 ora (vid_ptr),y eor cursor_bits+2 sta (vid_ptr),y dex : ldy cursor_y2 drnext: dec left_bytes dec left_bytes dey cpy cursor_y1 beq lowscr_rts jmp dloop .endproc drts: rts active_cursor := draw_cursor::active_cursor active_cursor_mask := draw_cursor::active_cursor_mask .proc restore_cursor_background lda cursor_count ; already hidden? bne drts bit cursor_flag bmi drts COPY_BYTES 4, cursor_data, cursor_bytes ldx #$23 ldy cursor_y2 cloop: cpy #192 bcs cnext lda hires_table_lo,y sta vid_ptr lda hires_table_hi,y ora #$20 sta vid_ptr+1 sty cursor_y2 ldy cursor_bytes lda cursor_softswitch jsr set_switch bcs :+ lda cursor_savebits,x sta (vid_ptr),y dex : jsr switch_page bcs :+ lda cursor_savebits,x sta (vid_ptr),y dex : jsr switch_page bcs :+ lda cursor_savebits,x sta (vid_ptr),y dex : ldy cursor_y2 cnext: dey cpy cursor_y1 bne cloop .endproc lowscr_rts: sta LOWSCR rts .proc switch_page lda set_switch_sta_addr eor #1 cmp #(screen_width-1) sbc drag_initialpos::xcoord+1 bmi no_grow sec lda #<(screen_height-1) sbc drag_initialpos::ycoord lda #>(screen_height-1) sbc drag_initialpos::ycoord+1 bmi no_grow jsr position_kbd_mouse jsr stash_cursor plp rts no_grow: lda #0 sta kbd_mouse_state lda #MGTK::Error::window_not_resizable plp jmp exit_with_a do_drag: lda current_winfo::options and #MGTK::Option::dialog_box beq no_dialog lda #0 sta kbd_mouse_state exit_call MGTK::Error::window_not_draggable no_dialog: ldx #0 dragloop: clc lda winrect::x1,x cpx #2 beq is_y adc #$23 jmp :+ is_y: adc #5 : sta kbd_mouse_x,x sta drag_initialpos,x sta drag_curpos,x lda winrect::x1+1,x adc #0 sta kbd_mouse_x+1,x sta drag_initialpos+1,x sta drag_curpos+1,x inx inx cpx #4 bcc dragloop bit kbd_mouse_x+1 bpl xpositive ldx #1 lda #0 : sta kbd_mouse_x,x sta drag_initialpos,x sta drag_curpos,x dex bpl :- xpositive: jsr position_kbd_mouse jsr stash_cursor plp rts .endproc .proc kbd_mouse_add_to_y php clc adc kbd_mouse_y sta kbd_mouse_y plp bpl yclamp cmp #(screen_width-1) bmi out_of_bounds lda #>(screen_width-1) sta kbd_mouse_x+1 lda #<(screen_width-1) sta kbd_mouse_x out_of_bounds: jmp position_kbd_mouse not_right: cmp #CHAR_LEFT bne not_left jsr kbd_mouse_check_xmin bcc out_of_boundsl lda kbd_mouse_x bit set_input_modifiers bpl :+ sbc #64 jmp move_left : sbc #8 move_left: sta kbd_mouse_x lda kbd_mouse_x+1 sbc #0 sta kbd_mouse_x+1 bpl out_of_boundsl lda #0 sta kbd_mouse_x sta kbd_mouse_x+1 out_of_boundsl: jmp position_kbd_mouse not_left: sta set_input_key COPY_STRUCT MGTK::GrafPort, $A7, $0600 lda set_input_key jsr kbd_menu_by_shortcut php COPY_STRUCT MGTK::GrafPort, $0600, $A7 plp bcc :+ lda #$40 sta movement_cancel jmp restore_cursor : rts .endproc .proc set_input MGTK_CALL MGTK::PostEvent, set_input_params rts .endproc .proc set_input_params ; 1 byte shorter than normal, since KEY state: .byte MGTK::EventKind::key_down key: .byte 0 modifiers: .byte 0 .endproc set_input_key := set_input_params::key set_input_modifiers := set_input_params::modifiers ;; Set to true to force the return value of check_if_changed to true ;; during a tracking operation. force_tracking_change: .byte 0 .proc kbd_mouse_check_xmin lda kbd_mouse_state cmp #kbd_mouse_state_mousekeys beq ret_ok lda kbd_mouse_x bne ret_ok lda kbd_mouse_x+1 bne ret_ok bit drag_resize_flag bpl :+ ret_ok: sec rts : jsr get_winframerect lda winrect::x2+1 bne min_ok lda #9 bit set_input_params::modifiers bpl :+ lda #65 : cmp winrect::x2 bcc min_ok clc rts min_ok: inc force_tracking_change clc lda #8 bit set_input_params::modifiers bpl :+ lda #64 : adc drag_initialpos sta drag_initialpos bcc :+ inc drag_initialpos+1 : clc rts .endproc .proc kbd_mouse_check_xmax lda kbd_mouse_state cmp #kbd_mouse_state_mousekeys beq :+ bit drag_resize_flag bmi :+ lda kbd_mouse_x sbc #<(screen_width-1) lda kbd_mouse_x+1 sbc #>(screen_width-1) beq is_max sec : sec rts is_max: jsr get_winframerect sec lda #<(screen_width-1) sbc winrect::x1 tax lda #>(screen_width-1) sbc winrect::x1+1 beq :+ ldx #256-1 : bit set_input_modifiers bpl :+ cpx #100 bcc clc_rts bcs ge_100 : cpx #44 bcc clc_rts bcs in_range clc_rts: clc rts ge_100: sec lda drag_initialpos sbc #64 jmp :+ in_range: sec lda drag_initialpos sbc #8 : sta drag_initialpos bcs :+ dec drag_initialpos+1 : inc force_tracking_change clc rts .endproc grew_flag: .byte 0 .proc set_grew_flag lda #$80 sta grew_flag grts: rts .endproc .proc finish_grow bit kbd_mouse_state bpl set_grew_flag::grts bit grew_flag bpl set_grew_flag::grts jsr get_winframerect php sei ldx #0 : sub16lc winrect::x2,x, #4, kbd_mouse_x,x inx inx cpx #4 bcc :- jsr position_kbd_mouse plp rts .endproc ;;; ============================================================ ;;; ScaleMouse ;;; Sets up mouse clamping ;;; 2 bytes of params, copied to $82 ;;; byte 1 controls x clamp, 2 controls y clamp ;;; clamp is to fractions of screen (0 = full, 1 = 1/2, 2 = 1/4, 3 = 1/8) (why???) .proc ScaleMouseImpl PARAM_BLOCK params, $82 x_exponent: .res 1 y_exponent: .res 1 END_PARAM_BLOCK lda params::x_exponent sta mouse_scale_x lda params::y_exponent sta mouse_scale_y set_clamps: bit no_mouse_flag ; called after INITMOUSE bmi end lda mouse_scale_x asl a tay lda #0 sta mouse_x sta mouse_x+1 bit mouse_hooked_flag bmi :+ sta CLAMP_MIN_LO sta CLAMP_MIN_HI : lda clamp_x_table,y sta mouse_y bit mouse_hooked_flag bmi :+ sta CLAMP_MAX_LO : lda clamp_x_table+1,y sta mouse_y+1 bit mouse_hooked_flag bmi :+ sta CLAMP_MAX_HI : lda #CLAMP_X ldy #CLAMPMOUSE jsr call_mouse lda mouse_scale_y asl a tay lda #0 sta mouse_x sta mouse_x+1 bit mouse_hooked_flag bmi :+ sta CLAMP_MIN_LO sta CLAMP_MIN_HI : lda clamp_y_table,y sta mouse_y bit mouse_hooked_flag bmi :+ sta CLAMP_MAX_LO : lda clamp_y_table+1,y sta mouse_y+1 bit mouse_hooked_flag bmi :+ sta CLAMP_MAX_HI : lda #CLAMP_Y ldy #CLAMPMOUSE jsr call_mouse end: rts clamp_x_table: .word screen_width-1, screen_width/2-1, screen_width/4-1, screen_width/8-1 clamp_y_table: .word screen_height-1, screen_height/2-1, screen_height/4-1, screen_height/8-1 .endproc ;;; ============================================================ ;;; Locate Mouse Slot ;; If X's high bit is set, only slot in low bits is tested. ;; Otherwise all slots are scanned. .proc find_mouse txa and #$7F beq scan jsr check_mouse_in_a sta no_mouse_flag beq found ldx #0 rts ;; Scan for mouse starting at slot 7 scan: ldx #7 loop: txa jsr check_mouse_in_a sta no_mouse_flag beq found dex bpl loop ldx #0 ; no mouse found rts found: ldy #INITMOUSE jsr call_mouse jsr ScaleMouseImpl::set_clamps ldy #HOMEMOUSE jsr call_mouse lda mouse_firmware_hi and #$0F tax ; return with mouse slot in X rts ;; Check for mouse in slot A .proc check_mouse_in_a ptr := $88 ora #>$C000 sta ptr+1 lda #<$0000 sta ptr ldy #$0C ; $Cn0C = $20 lda (ptr),y cmp #$20 bne nope ldy #$FB ; $CnFB = $D6 lda (ptr),y cmp #$D6 bne nope lda ptr+1 ; yay, found it! sta mouse_firmware_hi asl a asl a asl a asl a sta mouse_operand return #$00 nope: return #$80 .endproc .endproc no_mouse_flag: ; high bit set if no mouse present .byte 0 mouse_firmware_hi: ; e.g. if mouse is in slot 4, this is $C4 .byte 0 mouse_operand: ; e.g. if mouse is in slot 4, this is $40 .byte 0 ;;; ============================================================ ;;; GetDeskPat .proc GetDeskPatImpl ldax #desktop_pattern jmp store_xa_at_params .endproc ;;; ============================================================ ;;; SetDeskPat .proc SetDeskPatImpl ldy #.sizeof(MGTK::Pattern)-1 : lda (params_addr),y sta desktop_pattern,y dey bpl :- rts .endproc ;;; ============================================================ .endproc ; mgtk ;; Room for future expansion PAD_TO $8580