a2d/preview/show.image.file.s

724 lines
18 KiB
ArmAsm

.setcpu "65C02"
.include "apple2.inc"
.include "../inc/apple2.inc"
.include "../inc/prodos.inc"
.include "../mgtk.inc"
.include "../desktop.inc"
.include "../macros.inc"
;;; ============================================================
;;; Memory map
;;;
;;; Main Aux
;;; : : : :
;;; | | | |
;;; | DHR | | DHR |
;;; $2000 +-----------+ +-----------+
;;; | IO Buffer | |Win Tables |
;;; $1C00 +-----------+ | |
;;; $1B00 | | +-----------+
;;; | | | |
;;; | | | |
;;; | MP Dst | | MP Dst |
;;; $1580 +-----------+ +-----------+
;;; | | | |
;;; | MP Src | | |
;;; $1100 +-----------+ +-----------+
;;; | | | |
;;; | DA | | DA (Copy) |
;;; $800 +-----------+ +-----------+
;;; : : : :
;;;
hires := $2000 ; HR/DHR images are loaded directly into screen buffer
hires_size = $2000
;; Minipix/Print Shop images are loaded/converted
minipix_src_buf = $1200 ; Load address
minipix_src_size = 576
minipix_dst_buf = $1580 ; Convert address
minipix_dst_size = 26*52
.assert (minipix_src_buf + minipix_src_size) < minipix_dst_buf, error, "Not enough room for Minipix load buffer"
.assert (minipix_dst_buf + minipix_dst_size) < WINDOW_ICON_TABLES, error, "Not enough room for Minipix convert buffer"
;;; ============================================================
.org $800
da_start:
jmp start
save_stack:.byte 0
.proc start
tsx
stx save_stack
;; Copy DA to AUX
copy16 #da_start, STARTLO
copy16 #da_start, DESTINATIONLO
copy16 #da_end, ENDLO
sec ; main>aux
jsr AUXMOVE
;; Transfer control to aux
sta RAMWRTON
sta RAMRDON
;; Copy "call_main_template" routine to zero page
COPY_BYTES sizeof_routine+1, routine, call_main_trampoline
;; run the DA
jsr init
;; tear down/exit
sta RAMRDOFF
sta RAMWRTOFF
ldx save_stack
txs
rts
.endproc
call_main_trampoline := $20 ; installed on ZP, turns off auxmem and calls...
call_main_addr := call_main_trampoline+7 ; address patched in here
.proc routine
sta RAMRDOFF
sta RAMWRTOFF
jsr $1000 ; overwritten (in zp version)
sta RAMRDON
sta RAMWRTON
rts
.endproc
sizeof_routine = * - routine ; can't .sizeof(proc) before declaration
;; https://github.com/cc65/cc
;;; ============================================================
;;; ProDOS MLI calls
.proc open_file
jsr copy_params_aux_to_main
sta ALTZPOFF
MLI_CALL OPEN, open_params
sta ALTZPON
jsr copy_params_main_to_aux
rts
.endproc
.proc get_file_eof
jsr copy_params_aux_to_main
sta ALTZPOFF
MLI_CALL GET_EOF, get_eof_params
sta ALTZPON
jsr copy_params_main_to_aux
rts
.endproc
.proc read_file
jsr copy_params_aux_to_main
sta ALTZPOFF
MLI_CALL READ, read_params
sta ALTZPON
jsr copy_params_main_to_aux
rts
.endproc
.proc read_minipix_file
jsr copy_params_aux_to_main
sta ALTZPOFF
MLI_CALL READ, read_minipix_params
sta ALTZPON
jsr copy_params_main_to_aux
rts
.endproc
.proc close_file
jsr copy_params_aux_to_main
sta ALTZPOFF
MLI_CALL CLOSE, close_params
sta ALTZPON
jsr copy_params_main_to_aux
rts
.endproc
;;; ============================================================
;;; Copies param blocks from Aux to Main
.proc copy_params_aux_to_main
ldy #(params_end - params_start + 1)
sta RAMWRTOFF
loop: lda params_start - 1,y
sta params_start - 1,y
dey
bne loop
sta RAMRDOFF
rts
.endproc
;;; Copies param blocks from Main to Aux
.proc copy_params_main_to_aux
pha
php
sta RAMWRTON
ldy #(params_end - params_start + 1)
loop: lda params_start - 1,y
sta params_start - 1,y
dey
bne loop
sta RAMRDON
plp
pla
rts
.endproc
params_start:
;;; This block gets copied between main/aux
;;; ProDOS MLI param blocks
DEFINE_OPEN_PARAMS open_params, pathbuff, DA_IO_BUFFER
DEFINE_GET_EOF_PARAMS get_eof_params
DEFINE_READ_PARAMS read_params, hires, hires_size
DEFINE_READ_PARAMS read_minipix_params, minipix_src_buf, minipix_src_size
DEFINE_CLOSE_PARAMS close_params
.proc pathbuff ; 1st byte is length, rest is full path
length: .byte $00
data: .res 64, 0
.endproc
params_end:
;;; ----------------------------------------
da_window_id = 100
.proc line_pos
left: .word 0
base: .word 0
.endproc
event_params: .tag MGTK::Event
.proc window_title
.byte 0 ; length
.endproc
.proc winfo
window_id: .byte da_window_id ; window identifier
options: .byte MGTK::Option::dialog_box
title: .addr window_title
hscroll:.byte MGTK::Scroll::option_none
vscroll:.byte MGTK::Scroll::option_none
hthumbmax: .byte 32
hthumbpos: .byte 0
vthumbmax: .byte 32
vthumbpos: .byte 0
status: .byte 0
reserved: .byte 0
mincontwidth: .word screen_width
mincontlength: .word screen_height
maxcontwidth: .word screen_width
maxcontlength: .word screen_height
.proc port
viewloc: DEFINE_POINT 0, 0
mapbits: .addr MGTK::screen_mapbits
mapwidth: .word MGTK::screen_mapwidth
maprect: DEFINE_RECT 0, 0, screen_width, screen_height
.endproc
pattern:.res 8, 0
colormasks: .byte MGTK::colormask_and, MGTK::colormask_or
penloc: DEFINE_POINT 0, 0
penwidth: .byte 1
penheight: .byte 1
penmode: .byte MGTK::notpencopy
textback: .byte $7F
textfont: .addr DEFAULT_FONT
nextwinfo: .addr 0
.endproc
.proc init
copy #0, mode
;; Get filename by checking DeskTop selected window/icon
;; Check that an icon is selected
copy #0, pathbuff::length
lda selected_file_count
beq abort ; some file properties?
lda path_index ; prefix index in table
bne :+
abort: rts
;; Copy path (prefix) into pathbuff buffer.
: src := $06
dst := $08
asl a ; (since address table is 2 bytes wide)
tax
copy16 path_table,x, src
ldy #0
lda (src),y
tax
inc src
bne :+
inc src+1
: copy16 #(pathbuff::data), dst
jsr copy_pathbuff ; copy x bytes (src) to (dst)
;; Append separator.
lda #'/'
ldy #0
sta (dst),y
inc pathbuff::length
inc dst
bne :+
inc dst+1
;; Get file entry.
: lda selected_file_list ; file index in table
asl a ; (since table is 2 bytes wide)
tax
copy16 file_table,x, src
;; Exit if a directory.
ldy #2 ; 2nd byte of entry
lda (src),y
and #$70 ; check that one of bits 4,5,6 is set ???
;; some vague patterns, but unclear
;; basic = $32,$33, text = $52, sys = $11,$14,??, bin = $23,$24,$33
;; dir = $01 (so not shown)
bne :+
rts ; abort ???
;; Append filename to path.
: ldy #9
lda (src),y ; grab length
tax ; name has spaces before/after
dex ; so subtract 2 to get actual length
dex
clc
lda src
adc #11 ; 9 = length, 10 = space, 11 = name
sta src
bcc :+
inc src+1
: jsr copy_pathbuff ; copy x bytes (src) to (dst)
jmp open_file_and_init_window
.proc copy_pathbuff ; copy x bytes from src to dst
ldy #0 ; incrementing path length and dst
loop: lda (src),y
sta (dst),y
iny
inc pathbuff::length
dex
bne loop
tya
clc
adc dst
sta dst
bcc end
inc dst+1
end: rts
.endproc
.endproc
.proc open_file_and_init_window
jsr open_file
lda open_params::ref_num
sta get_eof_params::ref_num
sta read_params::ref_num
sta read_minipix_params::ref_num
sta close_params::ref_num
MGTK_CALL MGTK::HideCursor
MGTK_CALL MGTK::OpenWindow, winfo
MGTK_CALL MGTK::SetPort, winfo::port
jsr set_color_mode
jsr show_file
MGTK_CALL MGTK::ShowCursor
MGTK_CALL MGTK::FlushEvents
MGTK_CALL MGTK::ObscureCursor
;; fall through
.endproc
;;; ============================================================
;;; Main Input Loop
.proc input_loop
MGTK_CALL MGTK::GetEvent, event_params
lda event_params + MGTK::Event::kind
cmp #MGTK::EventKind::button_down ; was clicked?
beq exit
cmp #MGTK::EventKind::key_down ; any key?
beq on_key
bne input_loop
on_key:
lda event_params + MGTK::Event::modifiers
bne input_loop
lda event_params + MGTK::Event::key
cmp #CHAR_ESCAPE
beq exit
cmp #' '
bne :+
jsr toggle_mode
: jmp input_loop
exit:
jsr set_bw_mode
MGTK_CALL MGTK::HideCursor
;; Restore menu
MGTK_CALL MGTK::DrawMenu
sta RAMWRTOFF
sta RAMRDOFF
yax_call JUMP_TABLE_MGTK_RELAY, MGTK::HiliteMenu, last_menu_click_params
sta RAMWRTON
sta RAMRDON
;; Force desktop redraw
MGTK_CALL MGTK::CloseWindow, winfo
DESKTOP_CALL DT_REDRAW_ICONS
MGTK_CALL MGTK::ShowCursor
rts ; exits input loop
.endproc
.proc show_file
jsr get_file_eof
;; If bigger than $2000, assume DHR
lda get_eof_params::eof ; fancy 3-byte unsigned compare
cmp #<(hires_size+1)
lda get_eof_params::eof+1
sbc #>(hires_size+1)
lda get_eof_params::eof+2
sbc #^(hires_size+1)
bcc :+
jmp show_dhr_file
;; If bigger than 576, assume HR
: lda get_eof_params::eof
cmp #<(minipix_src_size+1)
lda get_eof_params::eof+1
sbc #>(minipix_src_size+1)
bcc :+
jmp show_hr_file
;; Otherwise, assume Minipix
: jmp show_minipix_file
.endproc
.proc show_hr_file
sta PAGE2OFF
jsr read_file
jsr close_file
jsr hr_to_dhr
rts
.endproc
.proc show_dhr_file
ptr := $06
;; AUX memory half
sta PAGE2OFF
jsr read_file
;; NOTE: Why not just load into Aux directly by setting
;; PAGE2ON? This works unless loading from a RamWorks-based
;; RAM Disk, where things get messed up. This is slightly
;; slower in the non-RamWorks case.
;; TODO: Load directly into Aux if RamWorks is not present.
;; Copy MAIN to AUX
sta CLR80COL ; read main, write aux
sta RAMRDOFF
sta RAMWRTON
copy16 #hires, ptr
ldx #>hires_size ; number of pages to copy
ldy #0
: lda (ptr),y
sta (ptr),y
iny
bne :-
inc ptr+1
dex
bne :-
sta RAMWRTON ; read aux, write aux
sta RAMRDON
sta SET80COL
;; MAIN memory half
sta PAGE2OFF
jsr read_file
jsr close_file
rts
.endproc
.proc show_minipix_file
jsr set_bw_mode
;; Load file at minipix_src_buf (MAIN $1800)
jsr read_minipix_file
jsr close_file
;; Convert (in main)
sta RAMWRTOFF
sta RAMRDOFF
jsr convert_minipix_to_bitmap
sta RAMWRTON
sta RAMRDON
;; Copy main>aux
copy16 #minipix_dst_buf, STARTLO
copy16 #minipix_dst_buf, DESTINATIONLO
copy16 #(minipix_dst_buf+minipix_dst_size), ENDLO
sec ; main>aux
jsr AUXMOVE
;; Draw
MGTK_CALL MGTK::PaintBits, paintbits_params
rts
minipix_width = 88 * 2
minipix_height = 52
.proc paintbits_params
viewloc: DEFINE_POINT (screen_width - minipix_width)/2, (screen_height - minipix_height)/2
mapbits: .addr minipix_dst_buf
mapwidth: .byte 26
reserved: .byte 0
maprect: DEFINE_RECT 0,0,minipix_width-1,minipix_height-1
.endproc
.endproc
;;; ============================================================
;;; Convert single hires to double hires
;;; Assumes the image is loaded to MAIN $2000 and
;;; relies on the hr_to_dhr.inc table.
.proc hr_to_dhr
ptr := $06
rows = 192
cols = 40
spill := $08 ; spill-over
lda #0 ; row
rloop: pha
tax
copy hires_table_lo,x, ptr
copy hires_table_hi,x, ptr+1
ldy #cols-1 ; col
copy #0, spill ; spill-over
cloop: lda (ptr),y
tax
bmi hibitset
;; complex case - need to spill in bit from prev col and store
lda hr_to_dhr_aux,x
sta PAGE2ON
sta (ptr),y
lda hr_to_dhr_main,x
ora spill ; apply previous spill bit (to bit 6)
sta PAGE2OFF
sta (ptr),y
ror ; move high bit to bit 6
and #(1 << 6)
sta spill
jmp next
hibitset:
;; simple case - no bit spillage
lda hr_to_dhr_aux,x
sta PAGE2ON
sta (ptr),y
lda hr_to_dhr_main,x
sta PAGE2OFF
sta (ptr),y
copy #0, spill ; no spill bit
next:
dey
bpl cloop
pla
inc
cmp #rows
bne rloop
;; TODO: Restore PAGE2 state?
done: sta PAGE2OFF
rts
.endproc
;;; ============================================================
;;; Minipix images
.proc convert_minipix_to_bitmap
rows = 52
cols = 88 ; pixels
src := $06
dst := $08
copy16 #minipix_src_buf, src
copy16 #minipix_dst_buf, dst
;; c/o Kent Dickey on comp.sys.apple2.programmer
;; https://groups.google.com/d/msg/comp.sys.apple2.programmer/XB0jUEvrAhE/loRorS5fBwAJ
ldx #rows
stx row
ldy #0 ; Y remains unchanged throughout
;; For each row...
dorow: ldx #8
stx srcbit
ldx #7
stx dstbit
ldx #cols
;; Process each bit
: jsr getbit
jsr putbit2
dex
bne :-
;; We've written out 88*2 bits = 176 bits. This means 1 bit was shifted into
;; the last bit. We need to get it from the MSB to the LSB, so it needs
;; to be shifted down 7 bits
: clc
jsr putbit1
dex
cpx #AS_BYTE(-7) ; do 7 times == 7 bits
bne :-
dec row
bne dorow
rts
.proc getbit
lda (src),y
rol
sta (src),y
dec srcbit
bne done
inc src
bne :+
inc src+1
: lda #8
sta srcbit
done: rts
.endproc
.proc putbit2
php
jsr putbit1
plp
;; fall through
.endproc
.proc putbit1
lda (dst),y
ror
sta (dst),y
dec dstbit
bne done
ror ; shift once more to get bits in right place
sta (dst),y
inc dst
bne :+
inc dst+1
: lda #7
sta dstbit
done: rts
.endproc
srcbit: .byte 0
dstbit: .byte 0
row: .byte 0
.endproc
;;; ============================================================
;;; Color/B&W Toggle
mode: .byte 0 ; 0 = B&W, $80 = color
.proc toggle_mode
lda mode
bne set_bw_mode
;; fall through
.endproc
.proc set_color_mode
lda mode
bne done
copy #$80, mode
copy16 #JUMP_TABLE_COLOR_MODE, call_main_addr
jsr call_main_trampoline
done: rts
.endproc
.proc set_bw_mode
lda mode
beq done
copy #0, mode
copy16 #JUMP_TABLE_MONO_MODE, call_main_addr
jsr call_main_trampoline
done: rts
.endproc
;;; ============================================================
.include "inc/hires_table.inc"
.include "inc/hr_to_dhr.inc"
;;; ============================================================
da_end: