;; ;; Image viewer, interfaces to jpeg decoder and displays image ;; in several different modes, also has output ;; of data to file option ;; ;; Copyright 2001, Raphael Espino ;; last updated 21-Feb-01 ;; ;; ---------- renderer zero page addresses, 192 and up are available rendpt = 192 ; pointer to image data - 2 bytes filtpt = 194 ; filter pointer - 2 bytes drawtemp = 196 ; 2 temporary storage bytes devpt = 198 ; 2 byte pointer to device name menupt = 200 ; 2 byte pointer to current menu options ;; ---------- end of renderer zero page addresses ;; ------------- decoder information addresses ------------------ DISPCOLS = $600 ; (# of columns to display)/8 must be <= 40 DISPROWS = $601 ; (# of rows to display)/8 coloff = $602 ; Coloumn offset to display image from rowoff = $603 ; Row offset to display image from numcols = $604 ; image width, 1 column = 8 pixels (pixels/8) numrows = $605 ; image height 1 row = 8 pixels (pixels/8) IOCBNUM = $606 ; IOCB to read jpeg data from STACKPT = $607 ; stack pointer at program start, use to return ; to DOS at any point ERROR = $608 ; non 0 if error ocurred decoding jpeg ; error codes are as defined in decoder RERUN = $609 ; 2 bytes - restart address, use to rerun decoder VERSION = $60B ; decoder version number MemTop = $60C ; End of decoder memory, memory >= MemTop is ; free for viewer when RendStart is called ; MemTop guaranteed to be below $8C00 ;; page 6 addresses from $630 up are available to renderer ;; ------------- end of decoder info addresses ---------------------- LODCHN = 2 ; IOCB to use for loading file SAVECHN = 3 ; IOCB to use for saving to file KEYBCHN = 4 ; IOCB to use for reading from keyboard ABORTCD = 128 ; code to tell decoder to abort LMARGN = 82 ROWCRS = 84 COLCRS = 85 SAVMSC = 88 VDSLST = 512 ; DLI vector VKEYBD = 520 ; keyboard IRQ vector SDLSTL = 560 GPRIOR = 623 ; priority register, enable GR.9 SDMCTL = 559 ; shadow DMA control address PCOLR0 = 704 ; colour shadow addresses COLOR0 = 708 COLOR1 = 709 COLOR2 = 710 COLOR3 = 711 COLOR4 = 712 CH = 764 ; last keypress shadow address ;; IOCB addresses ICCOM = 834 ICSTA = 835 ICBAL = 836 ICBAH = 837 ICBLL = 840 ICBLH = 841 ICAX1 = 842 ICAX2 = 843 MAXLEN = 64 ; max file name length RDBUF = $630 ; use page 6 for file name buffer COLPF1 = 53271 ; playfield 1 colour register COLPF2 = 53272 ; playfield 2 colour register PRIOR = 53275 ; priority register, enable GR.9/10 KBCODE = 53769 ; hardware keyboard code address PORTB = 54017 ; OS RAM control on XL/XE DMACTL = 54272 ; DMA control WSYNC = 54282 ; wait for scan line sync NMIEN = 54286 ; NMI enable CIOV = 58454 ; CIO vector SETVBV = 58460 ; Set VBI vector EXITIM = 58463 ; Exit Immediate VBI vector ;; ICCOM values OPEN = 3 ; open channel GETLNE = 5 ; get line GETBUF = 7 PUTLNE = 9 PUTBUF = 11 ; put buffer CLOSE = 12 ; close channel ;; IOCB open modes READ = 4 ; open for read READDIR= 6 ; open for directory read WRITE = 8 ; open for write DEBUG = 0 ;; set up viewer jmp vectors .ADDR segvector .ADDR segvectorend-1 .ORG $0620 segvector: ;; next 12 bytes should be JMP's to renderer's init, start, draw ;; and end code JMP RafRendInit ; init renderer JMP RafRendStart ; image data about to arrive JMP RafRendDraw ; 8 lines of image data available JMP RafRendEnd ; image completed JMP UnusedVec ; unused for now, point at an RTS segvectorend: ;; header for viewer .ADDR segcode .ADDR segcodeend-1 ;; renderer has area from $8C00 upwards for itself and screen .ORG $8C00 ;; ;; init code, this will be called when decoder starts or ;; when it is re-run. Renderer should display start up information, ;; open an IOCB for the decoder to read the jpeg data from ;; and store the (IOCB number * 16) in IOCBNUM ($606) ;; The rowoff and coloff values can optionally be set here ;; or in RendDraw. If they are not set they will default to 0 ;; DISPCOLS and DISPROWS can also optionally be set here or in ;; RendDraw. If not set they default to DISPCOLS = 40 (320 pixels) ;; DISPROWS = 24 (192 pixels) ;; *** DISPCOLS should NEVER be set to > 40 *** ;; segcode: RafRendInit: lda #64 sta NMIEN ; make sure DLIs are disabled lda #0 sta ROWCRS ;; display rendered information jsr strout .BYTE "a8jdpeg 0.5(21Feb01) Raphael Espino",155,155,155,0 lda repeat ; don't ask for filename if we are redisplaying beq @newfn jsr RestFN ; restore the previous one instead jsr strout .BYTE "Displaying ",0 jsr DispFN ; display filename too lda #0 ; ask user for filename next time round sta repeat ; by default sta wild beq openfl ; forced branch @newfn: jsr strout .BYTE "Add extra ':' at end for directory",155 .BYTE "File name:D:",0 jsr RDLINE ; get filename from user lda RDBUF+2 ; return to environment if no cmp #155 ; filename entered bne cont DOS: ldx STACKPT txs ldy #0 rts cont: ;; make sure IOCB is available jsr CloseInFile ;; now open the file stx IOCBNUM ; tell decoder what IOCB to use jsr CheckExt ; check if extension needs to be added to name ; also checks for ':' for directory lda wild bne dirop openfl: lda #READ .BYTE $2C ; ignore next 2 bytes dirop: lda #READDIR ldx #(LODCHN*16) jsr OpenFile bmi @error lda wild beq @savefn ; don't do a directory listing jsr DispDir jsr CloseInFile jmp (RERUN) @savefn: jmp SaveFN ; save file name and return to decoder ;; an error occured, display error code and restart @error: ldx #(LODCHN*16) lda ICSTA,X ; read status value pha ; remember error code jsr CloseInFile ; close file jsr strout .BYTE 155, "Error ",0 pla jsr DecOut ; display error code ; display file name too jsr strout .BYTE " - ",0 jsr DispFN ; display file name jmp WaitandRun ;; ;; renderer start code, will be called immediately before ;; the image data is about to start arriving. Renderer ;; should open graphics mode, open output file, etc. here. ;; This is the first point that numcols and numrows information ;; is valid. Renderer can optionally setup DISPCOLS, DISPROWS, ;; coloff, rowoff information here. ;; *** DISPCOLS should NEVER be set to > 40 *** ;; RafRendStart: lda #25 sta DISPROWS jsr strout ; display image size .BYTE 155,"Image width=",0 lda numcols jsr DecOut jsr strout .BYTE ", height=",0 lda numrows jsr DecOut ;; get column and row offsets from user jsr strout .BYTE 155,"Offset col:0",30, 0 jsr getnum ; get number from user sta coloff jsr strout .BYTE "Offset row:0",30,0 jsr getnum ; get number from user sta rowoff askagain: ;; display menu jsr strout .BYTE 155,"S KEY TOGGLES SCREEN WHILE DECODING",155 .BYTE "1) GR.8 - 40x25 2g 1/1",155 .BYTE "2) GR.15 - 20x25 4g 2/1",155 .BYTE "3) GR.15 - 40x25 4g 1/1",155 .BYTE "4) GR.9 - 10x25 16g 4/1",155 .BYTE "5) GR.9 - 20x25 16g 2/1", 155 .BYTE "6) GR.9 - 20x12 16g 1/1", 155 .BYTE 0 lda #7 ; 8 options available on 48K machines sta optlen jsr CKOSRAM ; is there any RAM under the OS? lda OSRAM bne @doram ; if so then display 64K options too jmp @noram @doram: jsr strout .BYTE "7) GR.8 - 40x25 4g 1/1 (64K)", 155 .BYTE "8) GR.15 - 20x25 9g 2/1 (64K)", 155 .BYTE "9) GR.15 - 40x25 9g 1/1 (64K)", 155 .BYTE "A) GR.9 - 10x25 31g 4/1 (64K)", 155 .BYTE "B) GR.9 - 20x25 31g 2/1 (64K)", 155 .BYTE "C) GR.9 - 20x12 31g 1/1 (64K)", 155 .BYTE "D) HIP - 20x25 30g 2/1 (64K)", 155 .BYTE "E) HIP - 40x25 30g 1/1 (64K)", 155 .BYTE 0 lda #15 ; 16 options available on 64K machines sta optlen @noram: jsr strout .BYTE "N) Run again",155 .BYTE "S) Save",155 .BYTE "Choice?" .BYTE 0 ldy prevopt ; if first time, then no previous selection bmi @noprev lda menuopts,y sta @displast ; display character for last menu selection lda ROWCRS pha sec ; start from top of menu ldx OSRAM bne @is64K sbc #8 ; 48K menu is 9 lines high .byte $2C @is64K: sbc #16 ; 64K menu is 17 lines high clc adc prevopt ; then find line of previous option ldx OSRAM beq @no64k ; position is already right for 48K mode cmp #15 ; options >=15 (64K options) are 2 lines higher bcc @ls15 sbc #2 ; carry is already set bne @no64k ; forced branch @ls15: cmp #13 ; options at pos < 13 are same 48K & 64K bcc @no64k clc ; options at pos 13-14 are 8 lines lower adc #8 ; there are 8 64K options @no64k: sta ROWCRS lda #1 sta COLCRS jsr strout .BYTE ">",0 lda #9 sta COLCRS pla sta ROWCRS jsr strout @displast: .BYTE " ",30,0 @noprev: lda #0 sta USE2SCR sta USEFILT jsr getmenu ; get user selection sta RENDMODE ; remember user selection jsr getaddr bcs @optfnd jmp askagain @optfnd: tya lsr cmp #6 ; don't remember last option for rerun beq @nosav sta prevopt @nosav: cpy #16 ; options >= 7-9 and A-E 2 screens rol USE2SCR lda @optadr,y pha dey lda @optadr,y pha rts @optadr: .WORD @gr8-1, @gr15-1, @gr15a-1, @gr9-1, @gr9a-1, @gr9a-1 .WORD runagain-1, @savetofile-1 .WORD @gr8-1, @gr15-1, @gr15a-1, @gr9-1, @gr9a-1, @gr9a-1 .WORD @hip-1, @hipa-1 @gr9a: inc USEFILT lda #20 .BYTE $2C @gr9: lda #10 ; 80/8 = 10 columns sta DISPCOLS lda #15 ; Graphics 9 jsr OpenGr lda #SCR2TMP sta gr9scr22+2 ldx #SCRADR sty gr9scr+2 sty gr9scr2+2 lda RENDMODE ; check if image is to be doubled vertically cmp #'6' ; modes 6 and 13 are beq @dogrd cmp #'C' bne @skgrd @dogrd: txa clc adc #40 sta gr9scrd+1 ; set up addresses for doubled data sta gr9scr2d+1 bcc @noiny iny @noiny: sty gr9scrd+2 sty gr9scr2d+2 ldy gr9scr22+2 lda gr9scr22+1 clc adc #40 sta gr9scr22d+1 bcc @no92d iny @no92d: sty gr9scr22d+2 lda #$9D ; enable doubling of data sta gr9scrd sta gr9scr2d sta gr9scr22d lda #80 sta LINEBYTES lda #12 sta DISPROWS bne @sknop @skgrd: lda #$EA ; NOP operation sta gr9scrd ; disable doubling of data sta gr9scrd+1 sta gr9scrd+2 sta gr9scr2d sta gr9scr2d+1 sta gr9scr2d+2 sta gr9scr22d sta gr9scr22d+1 sta gr9scr22d+2 lda #40 sta LINEBYTES @sknop: lda #64 sta GPRIOR ; enable gr.9 bne @exit @gr8: lda #15 ; Graphics 8 -> DL mode 15 jsr OpenGr ; open graphics mode lda #SCRADR sta gr8scr+2 lda #SCR2TMP sta gr8scr2+2 ;; graphics 8 colours are 0 and 1 lda #0 sta COLOR2 lda #8 sta COLOR1 bne @exit ; forced branch @gr15: lda #20 ; 160/8 = 20 columns sta DISPCOLS bne @skipfl @gr15a: ; leave DISPCOLS at default inc USEFILT @skipfl: lda #14 ; Graphics 15 -> DL mode 14 jsr OpenGr ; open graphics mode lda #SCRADR sta gr15scr+2 sta gr15scr2+2 lda #SCR2TMP sta gr15scr2b+2 ;; graphics 15 colours are 0, 1, and 2 + background (4) lda #4 sta COLOR0 lda #8 sta COLOR1 lda #12 sta COLOR2 @exit: ;; set up our own keyboard IRQ to toggle DMA if key pressed lda #0 sta SAVEDM lda VKEYBD ; save current keyboard IRQ for later sta OSKEYBIRQ+1 lda VKEYBD+1 sta OSKEYBIRQ+2 sei ; inhibit interrupts lda #dmatoggle sta VKEYBD+1 cli ; enable interrupts rts ;; save the data to a file @savetofile: jsr strout .BYTE 125,155,"1) Micropainter 2/1",155 .BYTE "2) Micropainter 1/1",155 .BYTE "3) HIP 2/1",155 .BYTE "4) HIP 1/1",155 .BYTE "5) 40x25 256g 1/1",155 .BYTE "N) Run again", 155 .BYTE "Choice?" .BYTE 0 ldy prevsave ; if first time, then no previous selection bmi @svnoprev lda svmenuopts,y sta @svdisplast ; display character for last menu selection lda ROWCRS pha sec ; start from top of menu sbc #6 ; menu is 7 lines high clc adc prevsave ; then find line of previous option sta ROWCRS lda #1 sta COLCRS jsr strout .BYTE ">",0 lda #9 sta COLCRS pla sta ROWCRS jsr strout @svdisplast: .BYTE " ",30,0 @svnoprev: jsr getmenu ; get user selection cmp #'N' bne @save jmp runagain @save: sta SAVEMODE jsr getsvaddr bcs @svoptfnd jmp @savetofile @svoptfnd: tya lsr cmp #6 ; don't remember last option for rerun beq @svnosav sta prevsave @svnosav: jsr strout .BYTE 155,"Save file name:D:",0 JSR RDLINE ; get filename from user ;; make sure IOCB is available JSR CloseOutFile BPL @ok jmp saveerr2 @ok: ;; now open the file LDA #WRITE jsr OpenFile bpl @ok2 jmp saveerr2 @ok2: lda #0 ; swtich screen off during save sta SDMCTL sta DMACTL lda #>SCRADR jsr clrscr lda #40 ; 320/8 = 40 columns sta DISPCOLS ldx SAVEMODE ; if lsbit is clear, then use filter dex ; set lsb for filter modes (2 and 4) txa ; it will be clear for rest (1, 3 and 5) lsr ; move lsb into carry rol USEFILT ; and then into USEFILT cmp #24 ; ((49 or 50)-1)/2 = 24 -> Micropainter beq @savmic cmp #25 ; ((51 or 52)-1)/2 = 25 -> HIP bne @jmexit sta savecount ; save 25 blocks worth (200 lines) lda #SCRADR sta hipscr2+2 ldx #(SAVECHN*16) ldy #8 ; save HIP header 1 jsr SetICBPut @jmexit: jmp @exit @savmic: ;; if saving in micropainter format, then save header lda #20 ; 160/8 = 20 columns sta DISPCOLS lda #24 sta DISPROWS sta savecount ; need to save 24 blocks worth lda #SCRADR sta gr15scr+2 jmp @exit ;; set up for drawing in HIP mode @hip: lda #20 ; 160/8 = 20 columns sta DISPCOLS bne @nofilt @hipa: inc USEFILT @nofilt: lda #15 ; Graphics 9 & 10 jsr OpenGr lda #SCR2TMP sta hipscr2+2 lda #SCRADR sta hipscr+2 lda #64 sta GPRIOR ; enable gr.9/10 ldx #8 @sthipc: lda @hipclrs,x ; set colour registers up for HIP sta 704,x dex bpl @sthipc jmp @exit @hipclrs: .BYTE 0,2,4,6,8,10,12,14,0 ; HIP colour values for regs 704-712 runagain: jsr CloseInFile ; close opened file jmp (RERUN) ; and rerun ;; handle keypresses during decoding of image dmatoggle: lda KBCODE and #%00111111 ; ignore Shift and Control keys cmp #40 ; 'r' aborts and reruns with same file bne @ckesc inc repeat bne @abort ; forced branch @ckesc: cmp #28 ; ESC key aborts bne @ckdma @abort: lda #ABORTCD ; tell decoder to abort sta ERROR bne OSKEYBIRQ @ckdma: cmp #62 ; toggle DMA if 's' key is pressed bne OSKEYBIRQ ; pass key press to OS txa pha lda SDMCTL ; toggle DMA value ldx SAVEDM stx SDMCTL stx DMACTL sta SAVEDM pla tax OSKEYBIRQ: jmp 30000 ; gets changed - jump to previous keyb IRQ SAVEDM: .BYTE 0 ; save previous DMA value RENDMODE: .BYTE 0 ; graphics mode menu selection SAVEMODE: .BYTE 0 ; last save operation type USE2SCR: .BYTE 0 ; use 2 screens? USEFILT: .BYTE 0 ; use filter? LINEBYTES: .BYTE 0 ; number of bytes to skip for next GR.9 line savecount: .BYTE 0 ; number of blocks saved so far prevopt: .BYTE 255 ; previous display option selected prevsave: .BYTE 255 ; previous save option selected ;; ;; draw image data. This gets called when 8 lines of image ;; data have been read and decoded from jpeg image. Renderer ;; should display/save/etc the 8 lines as it sees fit. Address ;; of data is in Acc (lo) and Y (hi). Data is 256 levels of ;; greyscale (8 bit luminance), 1 byte per pixel. Data is arranged ;; as 8 lines of 320 pixels ($A00 consecutive bytes). ;; If DISPCOLS < 40 then remaining data in line will be empty, i.e. ;; if DISPCOLS = 10 then each line will be 80 (10*8) bytes of image ;; data followed by 240 (30*8) bytes that should be ignored ;; *** DISPCOLS should NEVER be set to > 40 *** ;; RafRendDraw: sta rendpt ; save data buffer address sty rendpt+1 ldy #8 ; draw 8 lines sty rendline lda RENDMODE cmp #'S' bne @getadr lda SAVEMODE jsr getsvaddr lda @optsvadr2,y pha dey lda @optsvadr2,y pha rts @getadr: jsr getaddr lda @optadr2,y pha dey lda @optadr2,y pha rts @optadr2: .WORD rendgr8-1, rendgr15-1, rendgr15-1, rendgr9-1, rendgr9-1 .WORD rendgr9-1, 0, 0 .WORD rendgr8-1, rendgr152-1, rendgr152-1 .WORD rendgr92-1, rendgr92-1, rendgr92-1, rendhip-1, rendhip-1 @optsvadr2: .WORD rendgr15-1, rendgr15-1, rendhip-1, rendhip-1, savefile-1 ;; save data to file savefile: ldx #(SAVECHN*16) ; IOCB should already be open lda rendpt ; so just dump all data to file sta ICBAL,X lda rendpt+1 sta ICBAH,X lda #<(320*8) ; save 8 lines worth of data sta ICBLL,X lda #>(320*8) sta ICBLH,X jsr putbuf bpl @rts jmp saveerr ; error saving data @rts: UnusedVec: rts ;; draw data in gr.9 mode rendgr9: lda USEFILT beq @nofilt jsr filter ; reduce pixels horizontally @nofilt: ldy #0 ldx #0 gr9loop: lda (rendpt),y ; get 1st pixel and #%11110000 ; use top 4 bits for grey level sta drawtemp iny lda (rendpt),y ; get 2nd pixel lsr ; shift top 4 bits to the low 4 bits lsr ; of pixel data lsr lsr ora drawtemp gr9scr: sta 30000,x ; put pixel on screen gr9scrd: sta 30000,x ; double pixel vertically iny inx cpx #40 ; do 40 bytes worth of data at a time bcc gr9loop ; 40 bytes = 80 pixels lda gr9scr+1 ; move screen pointer onto next line clc adc LINEBYTES sta gr9scr+1 bcc @nogr9hi inc gr9scr+2 @nogr9hi: lda RENDMODE cmp #'6' bne @nogr9hi2 lda gr9scrd+1 ; move screen pointer onto next line clc adc #80 sta gr9scrd+1 bcc @nogr9hi2 inc gr9scrd+2 @nogr9hi2: ; move data pointer onto next line skip the other 240 bytes as they ; are empty jsr addtopt320 ; add 320 onto rendpt dec rendline ; have all 8 lines been drawn? bne rendgr9 ; no, go back and do the rest rts ;; draw data in HIP mode rendhip: lda RENDMODE cmp #'S' ; if we are saving, then use last 160 bytes bne @dodraw ; of 1st line and first 160 bytes of 2nd line clc ; for temporary disk buffer. This will work lda rendpt ; 'cos 1 line of disk buffer = 40 (8*40)=320 adc #160 ; and HIP only uses first 160 bytes (after sta svrend+1 sta hipsvclr+1 sta hipscr+1 ; filter) of every line, so by the time we use lda rendpt+1 ; space for disk buffer, data will already have adc #0 ; been extracted sta svrend2+1 sta hipsvclr+2 sta hipscr+2 bne dohip @dodraw: jsr OSRAMON dohip: lda USEFILT beq @nofilt jsr filter ; reduce pixels horizontally @nofilt: ldy #0 ldx #0 hiploop: lda (rendpt),y ; get 1st pixel and #%11110000 ; use top 4 bits for grey level sta drawtemp iny iny lda (rendpt),y ; get 2nd pixel lsr ; shift top 4 bits to the low 4 bits lsr ; of pixel data lsr lsr ora drawtemp hipscr: sta 30000,x ; put pixel on screen dey lda (rendpt),y ; get 1st pixel lsr ; only 9 colour registers in gr.10 so and #%01110000 ; use 3 bits for grey level (8 colours) sta drawtemp iny iny lda (rendpt),y ; get 2nd pixel lsr ; shift top 3 bits to the low 3 bits lsr ; of pixel data lsr lsr lsr ora drawtemp hipscr2: sta 30000,x ; put pixel on screen iny inx cpx #40 ; do 40 bytes worth of data at a time bcc hiploop lda hipscr+1 ; move screen pointer onto next line clc adc #40 sta hipscr+1 bcc @nohiphi inc hipscr+2 @nohiphi: lda hipscr2+1 ; move screen pointer onto next line clc adc #40 sta hipscr2+1 bcc @nohiphi2 inc hipscr2+2 @nohiphi2: jsr addtopt320 ; add 320 onto rendpt, moving it onto next line dec rendline ; have all 8 lines been drawn? bne dohip ; no, go back and do the rest lda RENDMODE cmp #'S' bne hipend dec savecount svrend: lda #0 ; gets changed, save block address lo svrend2: ldy #0 ; gets changed, save block address hi jsr saveblkadr bpl @lneclear jmp saveerr @lneclear: ; now clear out data saved in first 160 bytes lda #0 ; of second line in buffer. This needs to be tay ; done 'cos if jpeg is less than 160 pixels tax hipsvlp: dey ; wide, then this data won't be overwritten hipsvclr: sta 30000,y ; by next buffer full of data and will get bne hipsvlp ; saved to file as part of the image txa bne @rts inc hipsvclr+2 ldy #64 inx bne hipsvlp ; forced branch @rts: rts hipend: jmp OSRAMOFF ;; ;; draw data in gr.15 mode ;; rendgr15: lda USEFILT beq @nofilt jsr filter @nofilt: ldy #0 ldx #0 gr15loop: lda (rendpt),y ; get 1st pixel and #%11000000 ; use top 2 bits for grey level sta drawtemp iny lda (rendpt),y ; get 2nd pixel and #%11000000 ; use top 2 bits and shift into position lsr lsr ora drawtemp sta drawtemp iny lda (rendpt),y ; get 3rd pixel and #%11000000 lsr lsr lsr lsr ora drawtemp sta drawtemp iny lda (rendpt),y ; get 4th pixel rol rol rol and #%00000011 ora drawtemp gr15scr: sta 30000,x ; display on screen iny inx cpx #40 ; do 40 bytes worth of data bcc gr15loop lda USE2SCR beq @nogr152 jsr rendgr152 ; save data for 2nd GR.15 screen @nogr152: lda gr15scr+1 ; move screen pointer onto next line clc adc #40 sta gr15scr+1 bcc @nogr15hi inc gr15scr+2 @nogr15hi: jsr addtopt320 ; add 320 onto rendpt dec rendline ; have we done 8 lines yet? bne rendgr15 ; if not then go do the rest @chksv: lda RENDMODE cmp #'S' bne @rts dec savecount lda #SCRADR sta gr15scr+2 jsr saveblock ; dump 8 lines of data to disk bpl @rts jmp saveerr @rts: rts ;; draw data in gr.8 mode rendgr8: lda USE2SCR ; are we using 2 screens? beq dogr8 jsr OSRAMON dogr8: ldy #0 ldx #0 gr8loop: lda #0 sta drawtemp sta drawtemp+1 @pixlp: lda (rendpt),y ; get 1st pixel rol ; set GR.8 pixel if value >= 128 rol drawtemp rol rol drawtemp+1 iny tya and #%00000111 bne @pixlp lda drawtemp gr8scr: sta 30000,x tya bne @noinchi inc rendpt+1 @noinchi: lda USE2SCR beq gr8noram lda drawtemp+1 gr8scr2: sta 30000,x gr8noram: inx cpx #40 ; do 40 bytes worth of data bcc gr8loop lda gr8scr+1 ; move screen pointer onto next line clc adc #40 sta gr8scr+1 bcc @nogr8hi inc gr8scr+2 @nogr8hi: lda gr8scr2+1 ; move screen pointer onto next line clc adc #40 sta gr8scr2+1 bcc @nogr8hi2 inc gr8scr2+2 @nogr8hi2: lda #64 jsr addtopt ; move data pointer onto next line dec rendline beq @exit jmp dogr8 @exit: lda USE2SCR ; are we using 2 screens? beq @rts jsr OSRAMOFF ; yes, so disable OS RAM @rts: rts saveerr: jsr reset ; restore DMA + IRQ jsr OpenGr0 saveerr2: jsr strout .BYTE 155, "Save error ",0 ldx #(SAVECHN*16) lda ICSTA,x jsr DecOut jsr strout .BYTE 155,0 jsr CloseOutFile ; close output file jsr CloseInFile ; close input file jmp WRunMenu ; wait for key press and rerun ;; do a 1-2-1 filter on pixels to keep aspect ration in gr.15 filter: lda rendpt sta filtpt sta @destadr+1 lda rendpt+1 sta filtpt+1 sta @destadr+2 ldx #0 @filtlp: ldy #0 lda (filtpt),y ; get 1st pixel lsr ; divide it by 4 lsr sta drawtemp+1 iny lda (filtpt),y ; get 2nd pixel lsr ; divide it by 2 clc adc drawtemp+1 ; and add to pixel 2 cpx #159 ; make sure we don't go over right edge beq @destadr sta drawtemp+1 iny lda (filtpt),y ; get 3rd pixel lsr ; divide it by 4 lsr clc adc drawtemp+1 ; and add to pixel 1 + pixel 2 @destadr: sta 30000,x ; store result back at original pos clc lda filtpt ; and skip a pixel adc #2 sta filtpt bcc @noinchi inc filtpt+1 @noinchi: inx cpx #160 bcc @filtlp rts ;; ;; copy the second gr.15 screen to under the OS ;; rendgr152: jsr OSRAMON dogr152: lda USEFILT beq @nofilt jsr filter @nofilt: ldy #0 sty index gr152loop: jsr getpixel clc ror ror ror sta drawtemp txa clc ror ror ror sta drawtemp+1 jsr getpixel asl asl asl asl ora drawtemp sta drawtemp txa asl asl asl asl ora drawtemp+1 sta drawtemp+1 jsr getpixel asl asl ora drawtemp sta drawtemp txa asl asl ora drawtemp+1 sta drawtemp+1 jsr getpixel ora drawtemp pha txa ora drawtemp+1 ldx index gr15scr2b: sta 30000,x ; display on screen pla gr15scr2: sta 30000,x inx stx index cpx #40 ; do 40 bytes worth of data bcc gr152loop lda gr15scr2+1 ; move screen pointer onto next line clc adc #40 sta gr15scr2+1 bcc @nogr152hi inc gr15scr2+2 @nogr152hi: lda gr15scr2b+1 ; move screen pointer onto next line clc adc #40 sta gr15scr2b+1 bcc @nogr152bhi inc gr15scr2b+2 @nogr152bhi: jsr addtopt320 ; add 320 onto rendpt, moving it onto next line dec rendline ; have we done 8 lines yet? beq @skpjmp jmp dogr152 ; if not then go do the rest @skpjmp: jsr OSRAMOFF @rts: rts index: .BYTE 0 getpixel: lda (rendpt),y ; get 1st pixel iny and #%11110000 lsr lsr lsr lsr tax lda @lowclrtab,x pha lda @hiclrtab,x tax pla rts ;; C0 = 0, C1 = 2, C2 = 6, C3 = 8 ;; C0 = 0, C1 = 2, C2 = 4, C3 = 10 ;; 0 1 2 3 4 5 6 8 9 @lowclrtab: .BYTE 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 2, 3 @hiclrtab: .BYTE 0, 0, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3 ;; ;; copy the second gr.9 screen to under the OS ;; rendgr92: jsr OSRAMON dogr92: lda USEFILT beq @nofilt jsr filter ; reduce pixels horizontaly @nofilt: ldy #0 ldx #0 gr9loop2: lda #0 sta drawtemp sta drawtemp+1 lda (rendpt),y ; get 1st pixel and #%11110000 sta drawtemp sta drawtemp+1 lda (rendpt),y ; with 2 gr.9 screens we have 31 grey levels and #%00001000 ; or 5 bits worth. If 5th bit is clear then beq @noinc ; both screens have same colour lda drawtemp+1 cmp #240 ; if at max brightness, leave alone beq @noinc clc ; otherwise bump 2nd screen grey level up 1 adc #16 sta drawtemp+1 @noinc: iny lda (rendpt),y lsr lsr lsr lsr pha ora drawtemp sta drawtemp pla pha ora drawtemp+1 sta drawtemp+1 pla bcc @noinc2 and #%00001111 cmp #15 bcs @noinc2 inc drawtemp+1 @noinc2: lda drawtemp gr9scr2: sta 30000,x ; put pixel on screen gr9scr2d: sta 30000,x ; double pixel vertically lda drawtemp+1 gr9scr22: sta 30000,x ; put second pixel into temp memory gr9scr22d: sta 30000,x ; double pixel vertically iny inx cpx #40 ; do 40 bytes worth of data at a time bcc gr9loop2 ; 40 bytes = 80 pixels lda gr9scr2+1 ; move screen pointer onto next line clc adc LINEBYTES sta gr9scr2+1 bcc @nogr92hi inc gr9scr2+2 @nogr92hi: lda gr9scr22+1 ; move screen pointer onto next line clc adc LINEBYTES sta gr9scr22+1 bcc @nogr92hi2 inc gr9scr22+2 @nogr92hi2: lda RENDMODE cmp #'C' bne @nogr92hi4 @doscr2d: lda gr9scr2d+1 ; move screen pointer onto next line clc adc #80 sta gr9scr2d+1 bcc @nogr92hi3 inc gr9scr2d+2 @nogr92hi3: lda gr9scr22d+1 ; move screen pointer onto next line clc adc #80 sta gr9scr22d+1 bcc @nogr92hi4 inc gr9scr22d+2 @nogr92hi4: ; move data pointer onto next line skip the other 240 bytes as they ; are empty jsr addtopt320 ; add 320 onto rendpt dec rendline ; have all 8 lines been drawn? beq @exit jmp dogr92 ; no, go back and do the rest @exit: jmp OSRAMOFF rendline: .BYTE 0 ;; ;; end of data. Gets called when image has finished. Renderer ;; should close files, restore system back to original state, ;; wait for user to press a key and then return. After returning ;; decoder will exit back to environment (DOS). To restart decoder ;; instead do JMP (RERUN) instead of RTS. If decoder failed to ;; decode image then this will be called with ERROR > 0 ;; RafRendEnd: jsr reset ; reset IRQ and DMA ;; close input file jsr CloseInFile ldx #255 ; clear last key press stx CH inx stx COLOR4 ; set background colour to black lda RENDMODE cmp #'S' beq @dosave jmp notsave @dosave: lda ERROR ; check if user aborted bne @endsave ldx SAVEMODE dex txa lsr cmp #24 ; saving in Micropainter format beq @issav cmp #25 ; saving in HIP format beq @hipsave jmp @endsave ; must be mode 5 save @hipsave: lda savecount ; make sure we've saved enough data beq @saveclr lda #>SCR2ADR ldx #2 ; clear 2 pages worth jsr clrarea ; clear temporary data area for save @hiplp: lda #SCR2ADR jsr saveblkadr bmi @sverr dec savecount bne @hiplp ldx #(SAVECHN*16) ldy #12 ; save HIP header 2 jsr SetICBPut bmi @sverr ldy #0 jsr SetICBPut ; save 2nd screen to disk bmi @sverr bpl @endsave @issav: lda savecount ; make sure we've saved enough data beq @saveclr lda #>SCRADR ldx #2 ; clear 2 pages worth jsr clrarea ; clear temporary data area for save @savlp: jsr saveblock bpl @ok @sverr: jmp saveerr @ok: dec savecount bne @savlp @saveclr: ldx #(SAVECHN*16) ldy #16 jsr SetICBPut ; save colours (grey levels) for image @endsave: ;; we are saving to disk, so close file jsr CloseOutFile jsr OpenGr0 lda ERROR bne waitmsg jsr strout .BYTE 155,"Save complete",0 waitmsg: jsr strout .BYTE 155,0 lda ERROR cmp #ABORTCD beq rerun tax beq WRunMenu WaitandRun: lda #0 .BYTE $2C WRunMenu: lda #1 jsr WAITKEYP ; wait for key press rerun: jmp (RERUN) ; and rerun decoder notsave: ldx ERROR ; did decoder complete successfully? bne waitmsg LDY #IMVBI LDA #6 JSR SETVBV lda USE2SCR beq @waitkp ; if we copied data to OS RAM jsr copyscr ; then copy it back down again .if DEBUG lda #0 sta vbiscr ; reset VBI to display both screens .endif lda #64 sta NMIEN ; make sure DLIs are disabled lda RENDMODE cmp #'7' ; is this GR.8 mode? beq @gr8dli and #%11111110 cmp #'D' ; check for HIP mode (D and E) beq @hipdli cmp #'8' ; check for GR.15 modes (8 and 9) bne @waitkp lda #2 sta COLOR0 lda #4 sta dlicol1 lda #6 sta COLOR1 lda #8 sta COLOR2 lda #10 sta dlicol2 lda #GR15DLI bne @stupdl @gr8dli: lda #2 sta COLOR2 sta dlicol2 lda #6 sta COLOR1 lda #4 sta dlicol1 lda #GR8DLI bne @stupdl @hipdli: lda #HIPDLI @stupdl: sta VDSLST stx VDSLST+1 jsr setdli lda #192 sta NMIEN ; enable DLIs ;; get key press @waitkp: lda #0 lda CH and #%00111111 ; ignore Shift and Control keys cmp #28 ; ESC key - rerun decoder beq @exit cmp #33 ; SPACE BAR - rerun decode beq @exit cmp #22 beq @exit cmp #40 ; 'R' key repeats same image again beq @repeat .if DEBUG ;; disable this for release mode, only for debugging cmp #31 ; '1' key - display screen 1 in flicker modes beq @scr1 cmp #30 ; '2' key - display screen 2 in flicker modes beq @scr2 cmp #26 ; '3' key - display both scr in flicker modes beq @scr12 .endif cmp #6 ; + key beq @incclr cmp #14 ; - key bne @waitkp ; decrease colour number used ; leave luminance unchanged lda COLOR4 sec sbc #16 jmp @dorest .if DEBUG @scr1: lda #1 sta vbiscr bne @doagain @scr2: lda #255 sta vbiscr bne @doagain @scr12: lda #0 sta vbiscr beq @doagain .endif @repeat: inc repeat ; redisplay current image bne @exit @incclr: ; increase colour number used ; leave luminance unchanged lda COLOR4 clc adc #16 @dorest: sta COLOR4 inc changeclr @doagain: lda #255 sta CH jmp @waitkp @exit: pha LDY #EXITIM LDA #6 JSR SETVBV lda #64 sta NMIEN ; make sure DLI's are disabled ;; clear key press and return lda #255 sta CH pla cmp #22 ; if this was X key, then go do to DOS beq @rts jmp (RERUN) @rts: rts ;; reset IRQ and DMA reset: lda VKEYBD+1 cmp #>dmatoggle ; if IRQ was not put in place, bne @rts ; then leave it alone lda VKEYBD cmp #SCRADR bne @swscr1 ; only display screen 1 .endif @both: lda #>SCRADR ; if currently on screen 1, switch to 2 cmp DLADR+3 beq @swscr2 @swscr1: sta DLADR+3 ; otherwise switch to screen 1 lda #(>SCRADR)+16 sta DLADR+107 lda RENDMODE @ckhip: and #%11111110 cmp #'D' ; check for HIP mode (modes D and E) bne @swclr lda #64 ; HIP mode, so change DLI sta hipgr1+1 lda #128 sta hipgr2+1 bne @exit @swclr: .if DEBUG lda vbiscr ; check if scr 1, 2 or both should be displayed bne @exit ; display both screens alternately .endif lda COLOR1 ; swap colours for odd and even screen lines ldx dlicol1 ; around in 2 screen GR.8 and GR.15 modes stx COLOR1 sta dlicol1 lda COLOR2 ; don't need to do this for GR.8 but it doesn't ldx dlicol2 ; hurt do to it anyway and saves a few bytes stx COLOR2 sta dlicol2 @exit: pla tax jmp EXITIM @swscr2: ; switch to screen 2 lda #>SCR2ADR sta DLADR+3 lda #(>SCR2ADR)+16 sta DLADR+107 lda RENDMODE and #%11111110 cmp #'D' ; check for HIP mode (modes D and E) bne @swclr lda #128 ; HIP mode, so change DLI sta hipgr1+1 lda #64 sta hipgr2+1 jmp @exit changeclr: .byte 0 .if DEBUG vbiscr: .byte 0 ; display screen 1, 2 or both in flicker modes .endif ; display embeded string on screen ; string data should follow strout call and be terminated ; with a 0 strout: PLA ; get string address from stack TAY PLA TAX INY BNE @NIN2 INX @NIN2: STY ICBAL ; point at start of string STX @loop+2 STX ICBAH LDX #0 ; no data yet STX ICBLL STX ICBLH @loop: lda $c000,y ; - this address gets modified beq @exit ; continue until we find terminating 0 INC ICBLL ; increase length count bne @skplh inc ICBLH @skplh: iny bne @loop inc @loop+2 ; bump up to next page bne @loop @exit: TYA PHA jsr putbuf ; X should already be 0 PLA TAY ; modify return address to lda @loop+2 ; return immediately after pha ; terminating 0 tya pha rts ;; ;; use CIO to read a line of input from user ;; RDLINE: lda COLCRS ; remember current cursor pos - 2 sec sbc #2 sta @hpos lda ROWCRS sta @vpos jsr GetLine PHP lda SAVMSC sta devpt lda SAVMSC+1 sta devpt+1 ldy @vpos lda devpt @dvloop: dey ; calculate position on screen of bmi @vdone ; device name clc adc #40 bcc @dvloop inc devpt+1 bne @dvloop @vdone: sta devpt lda @hpos clc adc devpt sta devpt bcc @nopt1 inc devpt+1 @nopt1: ldy #1 @cpdev: lda (devpt),y ; get device name from screen jsr int2asc ; convert char to ASCII sta RDBUF,y ; add device name to buffer dey bpl @cpdev PLP BPL @EXTOK @EOL: ;; make sure there is a return char at end of line LDA #RDBUF ADC ICBLH,X STA @STA01+2 LDA #155 @STA01: STA 30000 ; GETS CHANGED @EXTOK: LDY #0 RTS @hpos: .BYTE 0 @vpos: .BYTE 0 ;; ;; get a line worth of data ;; GetLine: LDX #0 GetLineX: LDA #GETLNE ; read line of data into buffer into RDBUF+2 ldy #4 jmp SetICBICC ;; ;; convert a number from internal screen code to ASCII ;; int2asc: cmp #96 bcs @rts ; if >= 96 then don't change cmp #64 bcs @bit6 ; carry already clear adc #32 ; bit 6 not set, < 64, so add 32 rts @bit6: and #%10111111 ; if >= 64 and < 96 then clear bit 6 @rts: rts ;; ;; close IOCB ;; CloseInFile: ldx #(LODCHN*16) .BYTE $2C CloseOutFile: ldx #(SAVECHN*16) CloseChX: LDA #CLOSE STA ICCOM,X JMP CIOV ;; ;; wait for key press ;; WAITKEYP: pha jsr strout .BYTE 155,"Space - Run again",155 .BYTE "X - Exit to DOS",155,0 pla beq @nomenu jsr strout .BYTE "R - Redisplay",155,0 @nomenu: lda #255 sta CH @waitkpd: lda CH cmp #255 beq @waitkpd ldx #255 stx CH cmp #40 ; 'R' key bne @notr inc repeat ; redisplay current image @rerun: jmp (RERUN) @notr: cmp #33 ; Space key beq @rerun cmp #22 ; X key bne @nomenu jmp DOS ;; switch interrupts off and enable OS RAM OSRAMON: sei ; disable interrupts lda #0 sta NMIEN lda PORTB sta portbtmp and #%11111110 ; enable OS RAM sta PORTB rts portbtmp: .BYTE 0 ;; switch interrupts on and disable OS RAM OSRAMOFF: lda portbtmp sta PORTB lda #64 sta NMIEN cli rts DLADR = $630 ; display list address SCRADR = $A010 ; 1st screen address SCR2ADR = $5010 ; 2nd screen address SCR2TMP = $E000 ; temporary storage for screen 2 until ; decoder finishes ;; ;; open screen in appropriate graphics mode ;; graphics mode in y register ;; OpenGr: STA @mode ldy #0 lda #$60 sta DLADR,y iny lda #64 ; LMS clc adc @mode ; add in LMS screen mode sta DLADR,y iny lda #SCRADR sta DLADR,y ldy #202 lda @mode @filgr1: dey sta DLADR+4,y bne @filgr1 ldy #105 lda #64 ; LMS clc adc @mode ; add in LMS screen mode sta DLADR,y iny lda #0 sta DLADR,y ; set up data address for LMS iny lda #(>SCRADR)+16 sta DLADR,y ldy #205 lda #65 ; end the DL sta DLADR,y iny lda #dldata1 sta DLADR,y lda #>SCRADR ; clear screen memory area jsr clrscr ; clear 8k of ram lda USE2SCR ; check if temp scr area needs cleaning too beq @notmp jsr OSRAMON ; enable OS RAM lda #>SCR2TMP ; clear temp area too jsr clrscr jsr OSRAMOFF @notmp: lda #0 sta SDMCTL lda #dldata1 sta SDLSTL+1 lda #34 sta SDMCTL RTS @mode: .BYTE 0 ;; set up DLI interrups on every other display list line setdli: ldy #0 lda DLADR,y ora #128 sta DLADR,y ldy #4 @setdli: lda DLADR,y ora #128 sta DLADR,y iny iny cpy #105 bcc @setdli ldy #108 @setdli2: lda DLADR,y ora #128 sta DLADR,y iny iny cpy #205 bcc @setdli2 rts ;; first 2 lines of display list followed by a jump to page 6 ;; this won't fit in the space available in page 6 so have it here dldata1: .BYTE $60,$60,$1,$30,$06 ;; clear 8K worth of RAM for screen clrscr: ldx #32 ; 8K worth of screen data clrarea: sta filtpt+1 ; screen starting page ldy #0 tya sta filtpt @clrlp1: dey sta (filtpt),y bne @clrlp1 inc filtpt+1 dex bne @clrlp1 rts ;; ;; Print 1 byte decimal number on screen ;; DecOut: ldx #'0' ; initialise to ASCII char 0 stx reslt stx reslt+1 ldx #0 @numlp: cmp numtbl,X bcc @endb1 sbc numtbl,X ; carry already set inc reslt,X bne @numlp @endb1: inx cpx #2 bcc @numlp clc adc #'0' sta reslt+2 ldx #0 ldy #2 lda #'0' @fndst: cmp reslt,X bne @endlp inx dey bne @fndst @endlp: iny @disp: sty ICBLL lda #>reslt sta ICBAH txa clc adc # open file for read ;; Acc = 6 -> open for directory read ;; Acc = 8 -> open file for write ;; OpenFile: STA ICAX1,X ldy #24 ; open file, filename in RDBUF jmp SetICBOpen OSRTST = 52224 ; check this address to see if it is RAM or not ;; check if there is any RAM under the OS CKOSRAM: jsr OSRAMON LDY OSRTST ; PICK LOC. IN OS TO TEST LDX #255 STX OSRTST ; store $FF to test if it is RAM CPX OSRTST BNE @NTRAM ; not RAM INX STX OSRTST ; store 0 to test if it is RAM CPX OSRTST BNE @NTRAM ; not RAM STY OSRTST ; restore original value LDY #1 ; 1 FLAGS IT IS RAM BNE @ISRAM @NTRAM: STY OSRTST ; RESTORE JUST IN CASE LDY #0 @ISRAM: STY OSRAM jmp OSRAMOFF OSRAM: .BYTE 0 ;; copy screen data back down again from OS RAM copyscr: jsr OSRAMON lda #SCR2TMP sta rendpt+1 lda #SCR2ADR sta filtpt+1 ;; hip mode lines alternate GR.9/10/9/10... to reduce flickering lda #<(SCRADR+40) sta drawtemp lda #>(SCRADR+40) sta drawtemp+1 ldx #100 ; copy 200 lines worth, 2 at a time @hiplp: ;; copy even GR.10 lines (0,2,4...) over to screen 2 ldy #39 @hipcp: lda (rendpt),y sta (filtpt),y dey bpl @hipcp lda filtpt clc adc #40 sta filtpt bcc @nofhi inc filtpt+1 @nofhi: ;; copy odd GR.9 lines (1,3,5...) over to screen 2 ldy #39 @hipcp2: lda (drawtemp),y sta (filtpt),y dey bpl @hipcp2 jsr addtopt40 ; increase rendpt pointer by 40 bytes ;; copy odd GR.10 lines (1,3,5...) over to screen 1 ldy #39 @hipcp3: lda (rendpt),y sta (drawtemp),y dey bpl @hipcp3 lda filtpt clc adc #40 sta filtpt bcc @nofhi2 inc filtpt+1 @nofhi2: lda drawtemp clc adc #80 sta drawtemp bcc @nodhi inc drawtemp+1 @nodhi: jsr addtopt40 ; increase rendpt by 40 bytes dex bne @hiplp jmp OSRAMOFF ;; ;; check if extension needs to be added to filename ;; CheckExt: lda #0 sta wild ; no wild card found yet ldx ICBLL lda #':' ; find position of last ':' in filename @fndcln: ; not counting last character in filename ; anything before this will be device dex ; and directory name bmi @nocoln ; make sure we don't get into infinite loop cmp RDBUF,x ; if no ':' in filename bne @fndcln stx devlen ; remember position for later @nocoln: ldx ICBLL dex dex ; lda #':' cmp RDBUF+2,x ; if last char is ':' this is a dir command bne @chkdt ; not a dir command, check if extension needed dec ICBLL inc wild ; this is a dir command cmp RDBUF+1,x beq @dodir ; if two ':' are together at end, do *.JPG lda RDBUF+1 ; if last and 2nd char are both ':' cmp #':' ; then this is a dir command beq @gt1 cpx #1 ; beq @dodir ; if only ':' in filename, then do *.JPG bcs @gt1 ; if more than 1 char, this is a dir command jmp DOS ; otherwise go to DOS @gt1: lda #155 ; so replace that ':' with a return sta RDBUF+2,x @defd: dex bpl @chkdt inx @dodir: inc ICBLL lda #'*' sta RDBUF+2,x bne @addext @chkdt: lda #'.' cmp RDBUF+2,x ; if last char is '.' no extension needed bne @skpdt lda #155 ; so replace that '.' with a return sta RDBUF+2,x rts @skpdt: ldy #4 ; check last 4 characters @extlp: dex beq @addext ; end of name, add extension cmp RDBUF+2,x beq @rts ; extension is already there, ignore dey bne @extlp @addext: ldx ICBLL ldy #0 dex @cpextlp: lda @extname,y ; add extension to filename buffer beq @rts sta RDBUF+2,x inx iny bne @cpextlp @rts: rts @extname: .BYTE ".JPG",155,0 devlen: .byte 0 ; length of device + directory name in filename ;; set up IOCB, y register selects data to load into IOCB addresses SetICBOpen: lda #0 sta ICAX2,x lda #OPEN .byte $2C SetICBPut: ; set up IOCB for put buffer lda #PUTBUF SetICBICC: sta ICCOM,X SetICB: lda icbdat,y sta ICBAL,x lda icbdat+1,y sta ICBAH,x SetICBL: lda icbdat+2,y sta ICBLL,x lda icbdat+3,y sta ICBLH,x jmp CIOV ;; address, length icbdat: .WORD SCRADR, 8000 ; y=0 .WORD RDBUF+2, MAXLEN-6 ; y=4 .WORD hiphdr10, 6 ; y=8 .WORD hiphdr9, 6 ; y=12 .WORD micclrs, 6 ; y=16 .WORD K ; y=20 - 2 bytes .WORD E ; y=22 - 2 bytes .WORD RDBUF ; y=24 - 2 bytes, keep 24 and 26 together .WORD 0 ; y=26 - 2 bytes, keep 24 and 26 together .WORD 40 ; y=28 - 2 bytes ;; ;; check for a wild card in the file name, C set if wild card found ;; C clear if wild card not found ;; ; CheckDir: ; lda #0 ; sta wild ; no wild card found yet ; ldx ICBLL ; dex ; dex ; lda #':' ; cmp RDBUF+2,x ; if last char is ':' this is a dir command ; bne @rts ; lda #155 ; so replace that ':' with a return ; sta RDBUF+2,x ; inc wild ; rts ; lda #0 ; sta wild ; no wild card found yet ; ldx ICBLL ; dex ; @wldloop: ; dex ; bmi @rts ; lda RDBUF+2,x ; cmp #'*' ; beq @wldcard ; wild card found ; cmp #'?' ; bne @wldloop ; not found, go look at next character ; @wldcard: ; inc wild ; wild card found ; @rts: ; rts wild: .BYTE 0 ;; ;; display the disk directory using an open IOCB ;; DispDir: ldx #(KEYBCHN*16) ; open keyboard so we can read single keypress jsr CloseChX LDA #4 STA ICAX1,x lda #0 sta dirend ; directory end not found yet sta dircount ; not filenames read from directory yet ldy #20 jsr SetICBOpen ; this will set ICBLL/H as well, but they are ; ignored anyway lda #<(SCRADR+2) sta rendpt lda #>(SCRADR+2) sta rendpt+1 @dirlp: ldx #(LODCHN*16) @notlast: lda #GETLNE ; first read directory into buffer sta ICCOM,x lda rendpt sta ICBAL,x lda rendpt+1 sta ICBAH,x ldy #28 jsr SetICBL php ldy ICBLL,x iny lda #155 ; make sure there is a return char at end sta (rendpt),y ; of each filename jsr addtopt40 ; move onto next filename slot inc dircount ; and increase file count by one plp bpl @notlast dec dircount lda #SCRADR sta rendpt+1 @doagain: lda rendpt ; save start of screen full of data so sta filtpt ; we can find it again later lda rendpt+1 sta filtpt+1 lda #'A' ; menu entries start at 'A' sta lastdirc @nxtline: dec dircount bmi @dirend ; exit when end of list is reached bne @dsline inc dirend ; this is the last line, (FREE SECTORS line) @dsline: jsr displine ; display the line on screen inc lastdirc ; increase menu selection letter lda lastdirc cmp #'X' ; menu letters run from A-W bcc @nxtline @dirend: @prompt: jsr strout .BYTE "Space - continue, Esc - quit",0 @getagain: ldx #(KEYBCHN*16) lda #GETBUF ldy #24 ; set ICBLL/H to 0, don't care about ICBAL/H jsr SetICBICC ; get keypress cmp #32 ; is this a space? bne @ntspc lda dirend bne @jmexit beq @nextscr ; otherwise display next screen @ntspc: cmp #27 ; is this the Esc key? bne @skjmpx @jmexit: jmp @exit ; yes, so exit @skjmpx: cmp #'A' ; did user press a menu key? bcc @getagain cmp lastdirc bcs @getagain ; if not, then ignore keypress sec ; find position of user's selection sbc #'A' ; in the directory list tax lda filtpt ; point us back at start of this screen sta rendpt lda filtpt+1 sta rendpt+1 @findlp: dex bmi @found jsr addtopt40 ; add 40 onto rendpt jmp @findlp @found: ldy #2 ; we've found the line selected by user @skpspc: ; now find first non-space character on lda (rendpt),y ; that line, not counting menu letter iny cmp #32 beq @skpspc dey tya jsr addtopt ; point at first non-space char ldy #0 ; ldx #255 ldx devlen @restrlp: ; copy device info into last filename ; inx lda RDBUF,x sta lastfn,x ; cmp #':' dex bpl @restrlp ; inx ldx devlen inx @cplp: lda (rendpt),y ; copy file from storage area into last cmp #32 ; filename, skip any spaces beq @skspc sta lastfn,x inx @skspc: iny cpy #8 ; and don't do any more than 8 characters bcc @cplp lda (rendpt),y ; if there is a space here, then there isn't cmp #32 ; an extension beq @noext lda #'.' ; otherwise add '.' char for extender sta lastfn,x inx @cplp2: lda (rendpt),y ; now copy extender into filename cmp #32 ; if we find a space then finished beq @noext ; with extender cmp #'.' ; also skip any '.' chars, we've already beq @nostr ; got one of thoses sta lastfn,x @nostr: inx iny cpy #13 ; no more than 8+1+3 chars for filename bcc @cplp2 @noext: lda #155 ; end last filename with RETURN char sta lastfn,x inc repeat @bnexit: bne @exit @nextscr: jsr strout ; clear screen ready for next screen full .byte 125,0 jmp @doagain @exit: ldx #(KEYBCHN*16) ; close keyboard and exit jsr CloseChX rts K: .byte "K:" lastdirc: .byte 0 ; last character used in directory menu dirend: .byte 0 ; has end of directory been reached? dircount: .byte 0 ; number of entries in directory list ;; display character on directory menu displine: lda dirend bne @lstlne lda lastdirc ldx #')' bne @notlst @lstlne: dec lastdirc ; don't display letter next to last lda #' ' ; directory entry (# of free sectors) tax @notlst: ldy #0 sta (rendpt),y iny txa sta (rendpt),y lda rendpt STA ICBAL lda rendpt+1 STA ICBAH jsr putline jsr addtopt40 @noinhi: rts ;; ;; save filename for later ;; lastfn: .RES MAXLEN-2 SaveFN: ldx #MAXLEN dex @cpflnam: lda RDBUF,x ; copy filename from buffer to storage area sta lastfn,x dex bpl @cpflnam rts ;; ;; restore previously saved file name ;; RestFN: ldx #MAXLEN dex @cpflnam: lda lastfn,x ; copy filename from buffer to storage area sta RDBUF,x dex bpl @cpflnam rts repeat: .BYTE 0 ;; ;; display file name ;; DispFN: LDA #RDBUF STA ICBAH putline: LDA #PUTLNE ; write out file name STA ICCOM LDA #SCRADR saveblkadr: LDX #(SAVECHN*16) sta ICBAL,X tya sta ICBAH,X lda #<(40*8) sta ICBLL,X lda #>(40*8) sta ICBLH,X jmp putbuf getsvaddr: pha lda #svmenuopts ldy #6 bne skipmn ; forced branch getaddr: pha lda #menuopts ldy optlen skipmn: sta menupt stx menupt+1 pla @optloop: cmp (menupt),y ; check if key is on menu beq @optfnd dey bpl @optloop clc rts @optfnd: tya asl tay iny sec rts menuopts: .BYTE "1", "2", "3", "4", "5", "6", "N", "S" .BYTE "7", "8", "9", "A", "B", "C", "D", "E" svmenuopts: .BYTE "1", "2", "3", "4", "5", "N" optlen: .BYTE 0 ;; add value onto pointer addtopt320: inc rendpt+1 ; 320 = 256+64, increasing hi byte by 1 = 256 lda #<320 ; then add 64 into lo byte .byte $2c ; skip next instruction addtopt40: lda #40 addtopt: clc adc rendpt sta rendpt bcc @noinhi inc rendpt+1 @noinhi: rts ;; DLI routine for HIP modes HIPDLI: pha hipgr1: lda #64 ; gets changed during VBI sta WSYNC sta PRIOR ; enable either gr.9 or gr.10 hipgr2: lda #128 ; gets changed during VBI sta WSYNC ; wait for next horizontal blank sta PRIOR ; enable other mode for next line pla rti ; all done ;; DLI routine for GR.15 modes GR15DLI: pha txa pha lda COLOR1 ldx COLOR2 sta WSYNC sta COLPF1 stx COLPF2 lda dlicol1 ldx dlicol2 sta WSYNC ; wait for next horizontal blank sta COLPF1 stx COLPF2 pla tax pla rti ; all done ;; DLI routine for GR.8 modes GR8DLI: pha lda COLOR1 sta WSYNC sta COLPF1 lda dlicol1 sta WSYNC ; wait for next horizontal blank sta COLPF1 pla rti ; all done dlicol1: .BYTE 0 ; alternate colour register 1 used in DLI dlicol2: .BYTE 0 ; alternate colour register 2 used in DLI micclrs: .BYTE 0, 4, 8, 12 ; ; HIP file format is: ; hiphdr10, ; 8000 bytes of GR.10 screen, ; hiphdr9 ; 8000 bytes of GR.9 screen hiphdr10: .BYTE $FF, $FF, $10, $60, $4F, $7F hiphdr9: .BYTE $FF, $FF, $10, $80, $4F, $9F segcodeend: ;; end of renderer code .if (segcodeend > (SCRADR/256)*256) ;; there seems to be a bug in the .error command, so that giving it ;; a string constant causes an error, so do it this way instead .out .concat("Error - Code overrun into Screen area ", .string(*)) .error .else .out .concat("Code ends at ", .string(*)) .endif