====== ANIMTOOL ====== Part of [[Color Max Deluxe]] available from the [[https://www.colorcomputerarchive.com/|Color Computer Archive]] and in source form from [[https://github.com/milliluk/colormax]] Allows to load and view [[MGE]] files, and save memory buffers to MGE files. ===== ANNOTATED ASSEMBLY SOURCE ===== Original Source: [[https://github.com/milliluk/colormax/blob/master/ANIMTOOL.TXT]] NOTE: my comments may be wildly inaccurate. Please contact me on the [[http://discord.cocotalk.live|Color Computer Discord]] in the #programming channel if you have corrections. ;***************************************************************************** ;* ANIMTOOL ;***************************************************************************** NAM MGE file utility ; BEWARE !! ; ERIK'S BEEN HERE! ;***************************************************************************** ;* EQUATES ;***************************************************************************** PRSNXT: equ $9F ; Parse NEXT char PRSLST: equ $A5 ; Parse current char ;***************************************************************************** ; START ;***************************************************************************** START: lda $200 ; POKE &H200,frame # (0-12) cmpa #12 ; check for valid frame number (0-12) lbhi FNCERR ; >12 is a FN? error ;*********************************************** ; calculate graphics page numbers in Extended RAM lsla ; multiply frame number ... lsla ; ... by 4 (4 x 8KB blocks per image) pshs A ; ... and store on stack lda #$30 ; Now set up the default start 8K block num for frame 0 suba ,S+ ; subract the framebuffer size tfr A,B ; and move that to B for the first 8K block number of top half incb ; and make the second 8K block number of top half std GRP1+1,PCR ; set the two 8K block values for top half of frame adda #2 ; now add 2 to the first 8K block number addb #2 ; now add 2 to the second 8K block number std GRP2+1,PCR ; set the second two 8K block numbers for bottom half of frame ;*********************************************** jsr PRSLST ; Get next character from command line cmpa #': ; Is it the ':' we expect? lbne HELP ; No; show help and exit jsr PRSNXT ; look ahead one character cmpa #135 ; "?" TOKEN? lbeq INFO ; Yes, go show INFO and exit - same as help ;*********************************************** anda #$DF ; kill possible lowercase clrb ; flag for monitor type cmpa #'R ; RGB? beq A@ ; or cmpa #'C ; CMP? lbne SYNERR ; No; SN? error ldb #1 ; 1=CMP A@ stb MONTYP,PCR ; save 0=RGB or 1=CMP to MONTYPE ;*********************************************** jsr PRSNXT ; Get next character from command line cmpa #': ; Is it the ':' we expect? lbne SYNERR ; No; SN? error ;*********************************************** jsr PRSNXT ; Get next character from command line anda #$DF ; kill possible lowercase cmpa #'L ; LOAD? beq E@ ; or cmpa #'S ; SAVE? lbne SYNERR ; No; SN? error clra ; 0=SAVE, >0=LOAD E@ sta TODO,PCR ; store action in TODO ;*********************************************** jsr PRSNXT ; Get next character from command line cmpa #': ; Is it the ':' we expect? lbne SYNERR ; No; SN? error ;*********************************************** jsr PRSNXT ; Rest of the command is filename to work on lbsr PRSENM ; Parse the filename string lda TODO,PCR ; Now, are we loading or saving? Check TODO lbeq SVEPIX ; TODO=0 for SAVE so go do that ;*********************************************** ;* Start loading the picture ;*********************************************** lbsr OPENI ; open file - input lbsr GETBYT ; get MGE resolution byte tsta ; Not low-res! lbne BADRES ; Go report BADRES error and exit ;*********************************************** ; now - read in the 16 palettes* leax TEMP,PCR ; Point to temp place to store ldb #16 ; Going to read and save 16 values A@ lbsr GETBYT ; Go get one into A ... sta ,X+ ; ... and store it to where X points, then add 1 to X decb ; Count down one in palette read loop bne A@ ; Hit zero? No, go back and read next ;*********************************************** lbsr GETBYT ; Next byte is monitor type ;*********************************************** ; A now holds which monitor type that the picture was made on ; 0=RGB ; 1=composite ; Make 0/1 rather than 0/nz tsta ; So, what is file palette type? beq A@ ; Was A zero? if so, RGB and keep going lda #1 ; Force A to 1 for Composite rather than "anything not zero" A@ ;*********************************************** cmpa MONTYP,PCR ; Should I convert the palettes? lbeq NOCNV ; NOPE! File palette type matches our monitor leax RGBCMP,PCR ; Go from RGB to Composite? tsta ; Check previous result beq A@ ; Yes; skip next leax CMPRGB,PCR ; Go from Composite to RGB? A@ ;*********************************************** ; converts palettes from RGB to COMP or vice-versa leay TEMP,PCR ; Set Y to address of TEMP palette buffer ldb #16 ; Set our loop counter to size of palettes A@ lda ,Y ; Get file palette entry from addr in Y into A lda A,X ; Get matching conversion entry from table in X offset by A, back into A sta ,Y+ ; Store A to temp palette entry and move Y pointer to next in table decb ; Count down loop by 1 bne A@ ; Are we done? No; go back ;*********************************************** ; Don't convert NOCNV: ldy #$FFB0 ; Set Y to start of GIME palette registers leax TEMP,PCR ; Set X to start of TEMP palette buffer ldb #16 ; Set loop counter to 16 A@ lda ,X+ ; Load from TEMP into A and move X pointer 1 sta ,Y+ ; Start from A into GIME palette and move Y pointer by 1 decb ; Count down loop by 1 bne A@ ; Are we done? No; go back ;*********************************************** ; PALETTES ARE SET! ;*********************************************** ;*********************************************** lbsr GETBYT ; get compression flag pshs A ; Store on stack for a few ;*********************************************** ; ignore 32 byte picture-name* ldb #32 ; Set B to count 32 characters of file name A@ lbsr GETBYT ; Get a character decb ; Count down one bne A@ ; Done counting? ;*********************************************** puls A ; Get A back from stack tsta ; compressed? lbne NTCMP ; Nope; do non-compressed read ;*********************************************** ; COMPRESSED READ ; read in the bitmap ldx #$8000 ; Set X to start of framebuffer CMPLP: lbsr GETBYT ; get # of times to repeat tfr A,B ; Save repeat count into B lbsr GETBYT ; get byte to repeat tstb ; length=0?? beq CMPEND ; end.. close file and done lbsr GRPPGE ; page RAM in and ROM out A@ sta ,X+ ; repeat that decb ; byte.. bne A@ ; done repeating? No; go back lbsr NRMPGE ; yes; page back ROMs into memory map bra CMPLP ; Go back to get next repeat count and byte to repeat ;*********************************************** ; NON COMPRESSED READ ; read in bitmap NTCMP: ldx #$8000 ; Set X to start of framebuffer NTLP: lbsr GETBYT ; Get a byte from file lbsr GRPPGE ; flip pages - ROM out and RAM in sta ,X+ ; Store value from file direct to RAM lbsr NRMPGE ; flip back - ROM in and RAM out cmpx #$8000+32000 ; done? blo NTLP ; nope; go back and keep reading and drawing CMPEND: ; yes, time to finish lbsr CLOSE ; close the file rts ; and return to BASIC ;***************************************************************************** ; SAVE PIX ;***************************************************************************** SVEPIX: lbsr OPENO ; open file for output ;*********************************************** clra ; 0 for res=320x200 16 color lbsr WRTBYT ; Write that RES out to file ;*********************************************** ; write the palette out ldb #16 ; Set loop counter to 16 for palettes ldx #$FFB0 ; Setup to read from GIME palette registers A@ lda ,X+ ; Read from palette into A, then move pointer 1 lbsr WRTBYT ; Write palette value out to file decb ; Count down one in loop bne A@ ; Loop done? No; loop back ;*********************************************** ; write out the montype lda MONTYP,PCR ; MONTYPE 0=RGB, 1=CMP lbsr WRTBYT ; Write it to file ;*********************************************** ; no compression lda #255 ; COMPRESSION 0=compressed, not zero=uncompressed lbsr WRTBYT ; write it to file ;*********************************************** ; Bozo title leax UNT,PCR ; Set X to point to UNTitled file name buffer ldb #32 ; Set loop counter for 32 byte file name size R@ lda ,X+ ; Store the UNTitled buffer char to A and move X one lbsr WRTBYT ; Write title character to file decb ; Count down loop by one bne R@ ; Loop done? No; go back and keep writing name ;*********************************************** ; write out the bitmap ldx #$8000 ; Set X to point to start of bitmap A@ lbsr GRPPGE ; Page out ROM and expose bitmap RAM lda ,X+ ; Read a byte of bitmap into A and move X by 1 lbsr NRMPGE ; Page out bitmap RAM and restore ROM before ... lbsr WRTBYT ; ... using ROM to write the byte to file cmpx #$8000+32000 ; Has X reached end of bitmap? bne A@ ; No; go back and keep writing bitmap ;*********************************************** lbsr CLOSE ; Yes; done so close the file rts ; and return to basic ; Bozo title UNT: fcc "BASIC Pix",0 ;***************************************************************************** ;* BADRES ;* Tells 'em that they're in a bad resolution! ;***************************************************************************** org UNT+32 ; keep going after filename buffer ... A@ fcc "This file is at an incompatible",13 fcc "resolution",13,0 BADRES: leax A@,PCR ; Set pointer X to start of BADRES error message bsr PRTMS ; Print characters until NUL lbra FNCERR ; and exit to BASIC ROM FN? error ;***************************************************************************** ;* GRPPGE ;* Pages in graphics screen at ;* $8000.. Kills interrupts, too. ;***************************************************************************** GRPPGE: pshs X,D,Y,U ; Save registers to stack lda #52 ; Setup to ... sta $FF03 ; ... disable interrupts in PIA lda $FF02 ; ... and acknowledge any pending interrupt GRP1: ldd #$3031 ; Setup 8K blocks to ... std $FFA4 ; ... config MMU for extended RAM at 8000 and A000 GRP2: ldd #$3233 ; Setup 8K blocks to ... std $FFA6 ; ... config MMU for extended RAM at C000 and E000 puls X,D,Y,U,PC ; Restore registers and return ;***************************************************************************** ;* NRMPGE ;* Pages in normal memory ;* and re-enables interrupts. ;***************************************************************************** NRMPGE: pshs X,D,Y,U ; Save registers to stack ldd #$3C3D ; Setup 8K block numbers to ... std $FFA4 ; ... config MMU for ROM at 8000 and A000 ldd #$3E3F ; Setup 8K block numbers to ... std $FFA6 ; ... config MMU for ROM at C000 and E000 lda #53 ; Setup to ... sta $FF03 ; ... configure PIA for interrupts puls X,D,Y,U,PC ; Restore registers and return ;***************************************************************************** ;* OPENI ;* Opens a file for input ;* Entry: filename setup ;* Exit: file is opened! ;***************************************************************************** OPENI: pshs X,D,Y,U ; Save registers on stack ldx #$C959 ; Rom 1.0 file input ldd $C004 ; Which ROM??? Check DSKCON cmpd #$D66C ; Rom 1.0! beq A@ ; ! ldx #$CA07 ; Rom 1.1 file input A@ jsr ,X ; make call puls X,D,Y,U,PC ; Restore registers from stack and return ;***************************************************************************** ;* GETBYT ;* Gets a byte from the file ;* Entry: none ;* Exit : Byte's in A ;***************************************************************************** GETBYT: jmp $A176 ; COLOR BASIC ROM CONSOLE IN ;***************************************************************************** ;* WRTBYT ;* writes a byte to file ;***************************************************************************** WRTBYT: jmp [$A002] ; Indirect jump through CHROUT to ROM PUTCHR ;***************************************************************************** ;* OPENO ;* Open it for output ;***************************************************************************** OPENO: pshs X,D,Y,U ; Save registers on stack ldx #$C956 ; DECB 1.0 Open Sequential for I/O ldd $C004 ; Get value of DSKCON vector cmpd #$D66C ; Is it the DEBC ROM 1.0 version? beq A@ ; Yes; go open file for output ldx #$CA04 ; No; load addr of DECB 1.1 open A@ jsr ,X ; Go open the for output file using chosen ROM puls X,D,Y,U,PC ; Restore registers from stack and return ;***************************************************************************** ;* CLOSE ;* Closes an open file ;* Entry: None ;* Exit: None ;***************************************************************************** CLOSE: jmp $A42D ; COLOR BASIC ROM CLOSE FILE HANDLER ;***************************************************************************** ;* PRTMS ;* Enter: X pointing to msg ;* Exit : Well.. It PRINTS the msg! ;***************************************************************************** PRTMS: lda ,X+ ; Get next character to print from addr X+ into A beq ?RTS ; End of message (NUL)? yes; return jsr [$A002] ; No; print character bra PRTMS ; and keep going until we hit a NUL ;***************************************************************************** ;* PRSENM ;* Parse filename/extension:drivenumber using Disk BASIC ROM calls ;***************************************************************************** PRSENM: pshs X,D,Y,U ; Save regs on stack before use leax A@,PCR ; where is extension we're looking for? ldy #$C88A ; Address of Disk rom 1.0 get filename/ext ldd $C004 ; Look at what is stored in DSKCON vector cmpd #$D66C ; Izzit 1.0 beq B@ ; yep ldy #$C938 ; nope; setup addr of Disk rom 1.1 get filename/ext B@ jsr ,Y ; Call DECB ROM get filename/ext:drivenum puls X,D,Y,U,PC ; Restore regs from stack and return A@ fcc "MGE" ;***************************************************************************** ;* SYNTAX ERROR ;***************************************************************************** SYNERR: jmp $B277 ; ?SN ERROR ;***************************************************************************** ;* FUNCTION CALL ERROR ;***************************************************************************** FNCERR: jmp $B44A ; ?FC ERROR ;***************************************************************************** ;* PALETTE CONVERSION DATA ;***************************************************************************** RGBCMP: fcb 00,14,02,14,05,10,03,16,13,11,30,28,11,12,30,29 fcb 17,17,18,34,20,19,34,33,46,45,47,31,46,45,47,46 fcb 07,06,21,06,07,24,38,29,26,43,27,43,25,09,41,42 fcb 36,35,50,51,53,54,36,37,32,60,49,61,56,59,52,63 CMPRGB: fcb 00,02,02,06,00,04,33,32,32,45,05,09,13,08,01,00 fcb 07,16,18,21,20,34,38,36,37,44,40,42,11,15,10,27 fcb 56,23,19,49,48,55,38,39,37,46,47,41,11,25,24,26 fcb 63,58,50,51,62,52,53,60,60,46,61,61,57,59,58,63 TODO: rmb 1 ; 0=Load or !0=Save? TEMP: rmb 16 ; Temporarily hold 16 palette entries MONTYP: rmb 1 ; 0=RGB or !0=CMP ;***************************************************************************** ;* HELP / INFO ;***************************************************************************** A@ fcc "ANIMTOOL/BIN Version 1.0",13 fcc "(C) 1987 Milliluk Technologies",13 fcc "All rights reserved",13 fcc ' EXEC:montype:cmd:"name"',13 fcc " montype=R or C",13 fcc " cmd=S (save)",13 fcc " L (load)",13 fcc " POKE &H200,frame # (0-12)",13,0 HELP: INFO: jsr $A928 ; COLOR BASIC ROM CLEAR SCREEN leax A@,PCR ; Set pointer to start of help/info text above lbsr PRTMS ; Print characters using BASIC ROM until NUL jsr PRSNXT ; Go get next character (GETNCH at $9F) rts ; return to BASIC ;***************************************************************************** ;* END ;***************************************************************************** end START ===== RTS ===== Return to [[:Tandy Color Computer:]]